《Effective C++》学习笔记条款13 以对象管理资源

时间:2021-05-24 11:16:40
条款 13 :以对象管理资源

例:
     voidf()
     { 
         Investment *pInv = createInvestment(); 
         ...                  //这里存在诸多“不定因素”,可能造成delete pInv;得不到执行,这可能就存在潜在的内存泄露。
         delete pInv;
     }

 解决方法:把资源放进对象内,我们便可依赖C++的“析构函数自动调用机制”确保资源被释放。
    许多资源被动态分配于堆内而后被用于单一区块或函数内。它们应该在控制流离开那个区块或函数时被释放。标准

程序库提供的auto_ptr正是针对这种形势而设计的特制产品。auto_ptr是个“类指针对象”,也就是所谓的“智能指针”,

其析构函数自动对其所指对象调用delete。

void f()
     { 
        std::auto_ptr<Investment> pInv(createInvestment()); 
         ... 
     }         //函数退出,auto_ptr调用析构函数自动调用delete,删除pInv;无需显示调用delete。

“以对象管理资源”的两个关键想法:

  • 获得资源后立刻放进管理对象内(如auto_ptr)。每一笔资源都在获得的同时立刻被放进管理对象中。“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization;RAII)。
  • 管理对象运用析构函数确保资源被释放。即一旦对象被销毁,其析构函数被自动调用来释放资源。

由于auto_ptr被销毁时会自动删除它所指之物,所以不能让多个auto_ptr同时指向同一对象。所以auto_ptr若通

过copying函数复制它们,它们会变成NULL,而复制所得的指针将取得资源的唯一拥有权!

看下面例子:

std::auto_ptr<Investment> pInv1(createInvestment()); //pInv1指向createInvestment()返回物;
     std::auto_ptr<Investment>pInv2(pInv1);                     //现在pInv2指向对象,而pInv1被设为NULL;

pInv1 = pInv2;                                                           //现在pInv1指向对象,而pIn2被设为NULL;

受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它。即“有你没我,有我没你”。
      auto_ptr的替代方案是“引用计数型智能指针”(reference-counting smart pointer;SCSP)、它可以持续跟踪共有

多少对象指向某笔资源,并在无人指向它时自动删除该资源。

TR1的tr1::shared_ptr就是一个"引用计数型智能指针"。
     void f()
     { 
         ... 
        std::tr1::shared_ptr<Investment>  pInv1(createInvestment()); //pInv1指向createInvestment()返回物;
        std::tr1::shared_ptr<Investment> pInv2(pInv1);                    //pInv1,pInv2指向同一个对象;
         pInv1 = pInv2;                                                                     //同上,无变化
         ... 
     }        //函数退出,pInv1,pInv2被销毁,它们所指的对象也竟被自动释放。
       auto_ptr和tr1::shared_ptr都在其析构函数内做delete而不是delete[],也就意味着在动态分配而得的数组身上使

用auto_ptr或tr1::shared_ptr是个潜在危险,资源得不到释放。也许boost::scoped_array和boost::shared_array能提供

帮助。还有,vector和string几乎总是可以取代动态分配而得的数组。

请记住:

  • 为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。
  • 两个常被使用的RAII类分别是auto_ptr和tr1::shared_ptr。后者通常是较佳选择,因为其拷贝行为比较直观。若选择auto_ptr,复制动作会使他(被复制物)指向NULL。