千家信息网

C++的智能指针使用实例分析

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,今天小编给大家分享一下C++的智能指针使用实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来
千家信息网最后更新 2025年02月02日C++的智能指针使用实例分析

今天小编给大家分享一下C++的智能指针使用实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    什么是RAII

    RAII(Resource Acquisition Is Initialization)是由C++之父提出的,中文翻译为资源获取即初始化,使用局部对象来管理资源的技术称为资源获取即初始化;这里的资源主要是指操作系统中有限的东西如内存(heap)、网络套接字、互斥量、文件句柄等等,局部对象是指存储在栈的对象,它的生命周期是由操作系统来管理的,无需人工介入

    RAII的原理

    资源的使用一般经历三个步骤:

    • 获取资源(创建对象)

    • 使用资源

    • 销毁资源(析构对象)

    但是资源的销毁往往是程序员经常忘记的一个环节,所以程序界就想如何在程序中让资源自动销毁呢?解决问题的方案就是:RAII,它充分的利用了C++语言局部对象自动销毁的特性来控制资源的生命周期

    裸指针存在的问题

    1.难以区分指向的是单个对象还是一个数组

    2.使用完指针之后无法判断是否应该销毁指针,因为无法判断指针是否"拥有"指向的对象

    3.在已经确定需要销毁指针的情况下,也无法确定是用delete关键字删除,还是有其他特殊的销毁机制,例如通过将指针传入某个特定的销毁函数来摧毁指针

    4.即使已经确定了销毁指针的方法,由于1的原因,仍然无法确定到底是i用delete(销毁单个对象)还是delete[](销毁一个数组)

    5.假设上述的问题都解决了,也很难保证在代码的所有路径中(分支结构,异常导致的挑战),有且仅有一次销毁指针的操作;任何一条路径遗漏都可能导致内存的泄露,而销毁多次则会导致未定义行为

    6.理论上没有方法来分辨一个指针是否处于悬挂状态

    auto_ptr

    class Object{        int value;public:        Object(int x = 0) :value(x)        {                cout << "Create Object:" << this << endl;        }        ~Object()        {                cout << "Destory Object:" << this << endl;        }        int& Value()        {                return value;        }};templateclass my_auto_ptr{private:        bool _Owns;        _Ty* _Ptr;public:        my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)        {}        ~my_auto_ptr()        {                if (_Owns)                {                        delete _Ptr;                }                _Owns = false;                _Ptr = NULL;        }};void fun(){        my_auto_ptr obj(new Object(10));}int main(){        fun();}

    在这里将Object构建完成后,将其指针给到p,当函数结束去调动智能指针的析构函数去释放空间

    若我们需要在fun()函数中,去调用Object类的方法obj->Value();

    class Object{        int value;public:        Object(int x = 0) :value(x)        {                cout << "Create Object:" << this << endl;        }        ~Object()        {                cout << "Destory Object:" << this << endl;        }        int& Value()        {                return value;        }};templateclass my_auto_ptr{private:        bool _Owns;        _Ty* _Ptr;public:        my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)        {}        ~my_auto_ptr()        {                if (_Owns)                {                        delete _Ptr;                }                _Owns = false;                _Ptr = NULL;        }        _Ty* get()const        {                return _Ptr;        }        _Ty& operator*()const        {                return *(get());        }        _Ty* operator ->()const        {                return get();        }};void fun(){        my_auto_ptr obj(new Object(10));        cout << obj->Value() << endl;        cout << (*obj).Value() << endl;}int main(){        fun();}

    通过运算符重载,(*obj) 后将直接指向堆区(heap)的对象实体

    若我们通过一个my_auto_ptr去创建另一个my_auto_ptr

    class Object{        int value;public:        Object(int x = 0) :value(x)        {                cout << "Create Object:" << this << endl;        }        ~Object()        {                cout << "Destory Object:" << this << endl;        }        int& Value()        {                return value;        }};templateclass my_auto_ptr{private:        bool _Owns;        _Ty* _Ptr;public:        my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)        {}        ~my_auto_ptr()        {                if (_Owns)                {                        delete _Ptr;                }                _Owns = false;                _Ptr = NULL;        }        my_auto_ptr(const my_auto_ptr& obj):_Owns(obj._Owns),_Ptr(obj._ptr)        {               }        my_auto_ptr& operator=(const my_auto_ptr& _Y)        {                if(this == &_Y) return *this;                if(_Owns)                {                        delete _Ptr;                }                _Owns = _Y._Owns;                _Ptr = _Y._Ptr;                return 0;        }        _Ty* get()const        {                return _Ptr;        }        _Ty& operator*()const        {                return *(get());        }        _Ty* operator ->()const        {                return get();        }        void reset(_Ty* p = NULL)        {                if (_Owns)                {                        delete _Ptr;                }                _Ptr = p;        }        _Ty* release()const        {                _Ty* tmp = NULL;                if (_Owns)                {                        ((my_auto_ptr*)this)->_Owns = false; //常性进行修改                        tmp = _Ptr;                        ((my_auto_ptr*)this)->_Ptr = NULL;                }                return tmp;        }};void fun(){        my_auto_ptr pobja(new Object(10));        my_auto_ptr pobjb(pobja);}int main(){        fun();}

    如果通过浅拷贝,则两个指针拥有同一个资源,在析构的过程会造成资源的重复释放导致崩溃

    若设置为将其资源进行转移

    my_auto_ptr(const my_auto_ptr& obj):_Owns(obj._Owns),_Ptr(release()){}my_auto_ptr& operator=(const my_auto_ptr& _Y){        if(this == &_Y) return *this;        if(_Owns)        {                delete _Ptr;        }        _Owns = _Y._Owns;        _Ptr = _Y.release();        return 0;}
    void fun(my_auto_ptr apx){        int x = apx->Value();        cout< pobja(new Object(10));        fun(pobja);        int a = pobja->Value();        cout<

    那么上面的过程中,资源会进行转移pobja将不再拥有资源,导致pobja失去资源进而程序崩溃

    这也就是auto_ptr的局限性,也导致该智能指针的几乎没有使用

    unique_ptr

    该智能指针属于唯一性智能指针,将拷贝构造删除,也就不能将其新建另一个对象,同时也不能作为参数传入

    class Object{        int value;public:        Object(int x = 0) :value(x)        {                cout << "Create Object:" << this << endl;        }        ~Object()        {                cout << "Destory Object:" << this << endl;        }        int& Value()        {                return value;        }};int main(){        std::unique_ptr pobja(new Object(10));        //std::unique_ptr pobjb(pobja); error        //不允许        std::unique_ptr pobjb(std::move(pobja));}

    通过移动赋值是可以的,通过明确的概念,对其资源进行转移

    同时unique_ptr可以区分其所指向的是一个单独空间,或者是连续的空间

    struct delete_ar_object{        void operator()(Object* op)        {                if(op == NULL) return;                delete[] op;        }}int main(){        std::unique_ptr pobja(new Object(10));        std::unique_ptr pobjb(new Object[10]);}

    在这里如果是连续空间,会调用删除连续空间的删除器;单独空间则使用默认删除器

    unique_ptr在编写的时候,有多个模板类,分别对应单个对象的方案和一组对象的方案

    并且可以通过智能指针指向fopen打开的文件对象,而文件对象是同fclose去进行关闭的

    struct delete_file{        void operator()(FILE *fp)        {                if(fp == NULL) return;                fclose(fp);        }}std::unique_ptr pfile(fopen("zyq.txt","w"));

    这里只需要将默认的删除器,更改为对文件对象的删除器

    以上就是"C++的智能指针使用实例分析"这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。

    指针 资源 对象 智能 空间 指向 C++ 函数 文件 知识 程序 篇文章 单个 局部 方案 方法 还是 问题 实例 实例分析 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 如何学好控制网络技术基础 西安数据库培训哪里有 jsp软件开发设计思想 软件开发企业的利润一般是多少 法纪规范月保证书网络安全 河北大学网络安全每年的报录比 dellr710服务器级别 我的世界创造服务器招管理员 网络安全试卷内蒙古农业大学 wow服务器排队 网络安全法律卫士 防电信网络安全主题班会 甘肃人社人脸认证服务器配置 短视频需要多大服务器 嵌入式软件开发 工作描述 c数据库项目设计思路 怎么样打开数据库表中的隐藏表 软件开发企业技术部的职责 无线网络安全需求 世界互联网大会科技成果分享 南昌大学网络安全管理制度 数据库表怎么添加指定一列 甲基化数据库比对 电脑软件开发培训中心 上海科博达软件开发部加班吗 linux管理服务器的命令 陕西服务器硬盘代理商 河北张家口软件开发电脑学校 微信挂软件开发者 软件开发如何上门推销
    0