Effective C++(13) 用对象管理资源

问题聚焦:
从这条准则开始,都是关于资源管理的。
资源,一旦用了它,将来必须还给系统。
本条准则,基于对象的资源管理办法,建立在C++的构造函数,析构函数和拷贝函数(拷贝构造函数和重载赋值操作符)的基础上。


Demo: root class Investment:

class Investment { ... };
// 工厂函数
Investment* createInvestment();   // 返回指向一个Investment或者其子类的对象,调用者有责任删除它

// 考虑如下调用
void f() 
{
    Investment* pInv = createInvestment();
    ......
    delete pInv;      // 释放pInv所指的对象
}

问题:
当在delete语句调用之前出现return语句或者抛出异常并且该异常被默默地忽略掉时,这个对象便无法被释放。

解决思路:

C++的析构函数自动调用机制

方案一:类指针对象
标准程序库提供的 auto_ptr 是个“类指针对象”,也就是所谓的智能指针,其析构函数自动对所指对象调用delete。

void f()
{
    std::auto_ptr<Investment> pInv(createInvestment(( ));
    ......
}

关键:
获得资源后立刻放进管理对象:资源取得时机便是初始化时机
管理对象运用析构函数确保资源被释放:一旦对象被销毁(例如当对象离开作用域),其析构函数自然会被自动调用,于是资源被释放。
性质:唯一拥有权。
为了防止多个auto_ptr同时指向同一对象,auto_ptr有一个不同寻常的性质:若通过拷贝构造函数或重载赋值操作符复制它们,原指针会变成null,而复制所得的指针将取得资源的唯一拥有权。

 
void f()
{
    std::auto_ptr<Investment> pInv(createInvestment(( ));
    ......
}

方案二:引用计数型智慧指针RCSP
思想:持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。

void f()
{
    ...
    std::str1::shared_ptr<Investment> pInv(createInvestment());
    ...
}

区别:str1::shared_ptr的调用和auto_ptr相同,区别就是在复制行为上

void f()
{ 
    ......
    std::tr1::shared_ptr<Investment> pInv1(createInvestment());
    std::str1::shared_ptr<Investment> pInv2(pInv1);           // pInv1和pInv2指向同一对象
    pInv1 = pInv2;
}

需要格外注意下面这种错误用法:

std::auto_ptr<std::string> aps(new std::string[10]);
std::str1::shared_ptr<int> spi(new int[1024]);

错误原因:auto_ptr和str1::shared_ptr两者在其析构函数内做delete而不是delete[]动作。

格外指出:createInvestment返回”未加工指针“是个非常不好的接口设计,在后面的条款中会对这个接口进行修改。


小结:
为了防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
两个常被使用的RAIIclasses分别是tr1::shared_ptr和auto_ptr,前者通常是较佳选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它指向Null。


参考资料:
《Effective C++ 3rd》


 

posted @ 2014-01-02 09:32  suzhou  阅读(189)  评论(0编辑  收藏  举报