条款13:以对象管理资源

  假设我们使用一个用来塑模投资行为的程序库,其中各式各样的投资类型继承自一个root class Investment:

class Investment{...};                //"投资类型",继承体系中的root class 

  假设这个程序库通过一个工厂函数提供我们特定的Investment对象:

Investment* createInvesment();                //返回指针,指向Investment继承体系内的动态分配对        
                                              //象

  加入有个f函数调用了这个函数的返回对象并删除了它。

void f()
{
    Investment* pInv = createInvestment();        //调用factory
    ...
    delete pInv;                                  //释放pInv所指对象
}

  现在看来此处不会有问题。但是如果"..."区域有一个过早的return语句。如果这样的return语句执行起来,就不会触发delete语句。

  为了确保createInvestment返回的资源总是被释放,我们需要将资源放进对象内,当离开函数f时,该对象的析构函数就会自动释放那些资源。

  许多资源被动态分配于heap内而后被用于单一区域或函数内。它们应该被控制流离开那个区域或函数时被释放。标准程序库函数提供auto_ptr正是针对这种形式而设计。auto_ptr是个类指针对象,也就是所谓的智能指针。其析构函数自动调用其所指对象delete。

void f()
{
    std::auto_ptr<Investment> pInv(createInvestment());//经由auto_ptr的析构函数自动删除pInv
}

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

(1)  获得资源后立刻放进管理对象内。

     “以对象管理资源”的观念常常被称为“资源取得时机便是初始化时机”(Resource Acquiisition Is Initialzation;RAII)

(2)管理对象运用析构函数确保资源被释放。

 

  由于auto_ptr被销毁时会自动删除它所指之物,所以不要让多个auto_ptr同时指向同一对象。否则,对象会被删除一次以上。为了预防这个问题。auto_ptrs有一个不同寻常的性质:若通过copy构造函数或copy_assignment操作符复制它们,它们会变成null,而复制的指针将取得资源的唯一拥有权。

std::auto_ptr<Investment> pInv1(createInvestment());  //pInv1指向createInvestment返回


std::auto_ptr<Investmnet> pInv2(pInv1);        //现在pInv2指向对象,pInv1被设为null

pInv1 = pInv2;                                 //现在pInv1指向对象,pInv2被设为null

  auto_ptr的替代方案是“引用计数型智慧指针”(reference-counting smart pointer;RCSP)。所谓的RCSP也是个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除资源。

void f()
{
    ...
    std::tr1::shared_ptr<Investment>
    pInv(createInvestment);               //调用factroy,经由shared_ptr析构函数自动删除pInv
}

 这段代码看起来和auto_ptr的那个版本相同,但share_ptrs的复制行为正常多了:

void f()
{
    ...
    std::tr1::shared_ptr<Invesment>
    pInv1(createInvestment());                //pInv指向createInvestment返回物

    std::tr1shared_ptr<Investment> pInv2(pInv1);//pInv1和pInv2指向同一个对象
    pInv2(pInv1);                              // 同上,还是指向同一个对象

    ...                                     //pInv1和pInv2被销毁,它们所指的对象也就被自动销毁
}

auto_ptr 和tr1::shared_ptr两者都在其析构函数内做delete而不是delete[]动作。这就是说在动态分配而得的array身上使用auto_ptr或tr1::shared_ptr是个馊主意。但是能通过编译:

std::auto_ptr<std::string> aps(new std::string[10]);

std::tr1::shared_ptr<int> spi(new int[1024]);

  并没有针对C++动态分配数组而设计的类似auto_ptr或tr1::shared_ptr那样的东西。因为vector和string几乎总是可以取代动态分配而得的数组。

 

 结论:

  为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。

  两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr。前者通常是最佳选择,因为其copy行为比较直观。若选择auto_ptr,复制行为会使它(被复制物)指向null。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值