C++的智能指针使用实例分析(C++,开发技术)

时间:2024-05-08 21:25:15 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    什么是RAII

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

    RAII的原理

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

    • 获取资源(创建对象)

    • 使用资源

    • 销毁资源(析构对象)

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

    裸指针存在的问题

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

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

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

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

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

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

    auto_ptr

    classObject{ intvalue;public: Object(intx=0):value(x) { cout<<"CreateObject:"<<this<<endl; } ~Object() { cout<<"DestoryObject:"<<this<<endl; } int&Value() { returnvalue; }};template<class_Ty>classmy_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; }};voidfun(){ my_auto_ptr<Object>obj(newObject(10));}intmain(){ fun();}

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

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

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

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

    classObject{ intvalue;public: Object(intx=0):value(x) { cout<<"CreateObject:"<<this<<endl; } ~Object() { cout<<"DestoryObject:"<<this<<endl; } int&Value() { returnvalue; }};template<class_Ty>classmy_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 { returnget(); }};voidfun(){ my_auto_ptr<Object>obj(newObject(10)); cout<<obj->Value()<<endl; cout<<(*obj).Value()<<endl;}intmain(){ fun();}

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

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

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

    classObject{ intvalue;public: Object(intx=0):value(x) { cout<<"CreateObject:"<<this<<endl; } ~Object() { cout<<"DestoryObject:"<<this<<endl; } int&Value() { returnvalue; }};template<class_Ty>classmy_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(constmy_auto_ptr&obj):_Owns(obj._Owns),_Ptr(obj._ptr) { } my_auto_ptr&operator=(constmy_auto_ptr&_Y) { if(this==&_Y)return*this; if(_Owns) { delete_Ptr; } _Owns=_Y._Owns; _Ptr=_Y._Ptr; return0; } _Ty*get()const { return_Ptr; } _Ty&operator*()const { return*(get()); } _Ty*operator->()const { returnget(); } voidreset(_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; } returntmp; }};voidfun(){ my_auto_ptr<Object>pobja(newObject(10)); my_auto_ptr<Object>pobjb(pobja);}intmain(){ fun();}

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

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

    my_auto_ptr(constmy_auto_ptr&obj):_Owns(obj._Owns),_Ptr(release()){}my_auto_ptr&operator=(constmy_auto_ptr&_Y){ if(this==&_Y)return*this; if(_Owns) { delete_Ptr; } _Owns=_Y._Owns; _Ptr=_Y.release(); return0;}
    voidfun(my_auto_ptr<Object>apx){ intx=apx->Value(); cout<<x<<endl;}intmain(){ my_auto_ptr<Object>pobja(newObject(10)); fun(pobja); inta=pobja->Value(); cout<<a<<endl;}

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

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

    unique_ptr

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

    classObject{ intvalue;public: Object(intx=0):value(x) { cout<<"CreateObject:"<<this<<endl; } ~Object() { cout<<"DestoryObject:"<<this<<endl; } int&Value() { returnvalue; }};intmain(){ std::unique_ptr<Object>pobja(newObject(10)); //std::unique_ptr<Object>pobjb(pobja);error //不允许 std::unique_ptr<Object>pobjb(std::move(pobja));}

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

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

    structdelete_ar_object{ voidoperator()(Object*op) { if(op==NULL)return; delete[]op; }}intmain(){ std::unique_ptr<Object>pobja(newObject(10)); std::unique_ptr<Object,delete_ar_object>pobjb(newObject[10]);}

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

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

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

    structdelete_file{ voidoperator()(FILE*fp) { if(fp==NULL)return; fclose(fp); }}std::unique_ptr<FILE,delete_file>pfile(fopen("zyq.txt","w"));

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

     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:C++的智能指针使用实例分析的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:Vue框架中怎么调用模拟数据下一篇:

    9 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18