Item 13:Use objects to manage resources
假设我们使用一个用来塑膜投资行为的程序库,其中各式各样的投资类型继承自一个root class:
class Investment { ... }; //“投资类型”继承体系中的root class
进一步假设,这个程序系通过一个工厂函数(工厂函数会“返回一个base class指针,指向新生成的derived class 对象),供应我们某特定的Investment对象:
Investment* createInvestment( );
createInvestment的调用端使用了函数返回的对象后,有责任将其删除。现在考虑有个f函数履行了这个责任:
void f() { Investment* pInv = createInvestment(); //调用factory函数 ... delete pInv; //释放pInv所指对象 }
这看起来妥当,但若干情况下f可能无法删除它得自createInvestment的投资对象——或许因为”。。。“区域内的一个过早的return语句,又或者这个delete语句可能位于某循环内,而该循环由于某个continue或goto语句过早退出。无论delete如何被略过去,我们泄漏的不只是内含投资对象的那块内存,还包括那些投资对象所保存的任何资源。
而且一旦软件开始接受维护,可能会有人添加return语句或continue语句而未能全然领悟它对函数的资源管理策略造成的后果。因此单纯依赖”f总是会执行其delete语句是行不通的“。
为了解决这个问题,作者推荐了auto_ptr和shared_ptr两种智能指针。
auto_ptr是个”类指针对象“,其析构函数自动对其所指对象调用delete。下面师范如何使用:
void f() { std::auto_ptr<Investment> pInv(createInvestment()); //调用factory函数 ... } //经由auto_ptr的析构函数自动删除pInv
所谓“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”(即RAII),因为我们几乎总是在获得一笔资源后于同一语句内以它初始化某个管理对象。
//云风评注:使用auto_ptr时一定要小心。它解决的是在栈堆上使用指针引用一个对象后的安全释放问题。多个auto_ptr不能共享同一对象的所有权,也不能通过它引用一个对象数组等。auto_ptr有诸多问题,现在已经不推荐使用。在新的标准中,建议使用unique_ptr.//
auto_ptr有一个不同寻常的性质:若通过copy构造函数或copy assignment操作符复制它们,它们会变成NULL,而复制所得的指针将取得资源的唯一拥有权。
std::auto_ptr<Investment> pInv1(createInvestment()); std::auto_ptr<Investment> pInv2(pInv1);//现在pinv2指向对象,pInv1被设为NULL pInv1 = pInv2; //现在pInv1指向对象,pInv2被设为NULL
auto_ptr的替代方案是”引用技术型智慧指针“(RCSP)。所谓RCSP也是个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。然而RCSP无法打破环状引用,例如两个其实已经没被使用的对象彼此互指,因而好像还处在”被使用“状态。
最后,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]);
这两种方式都会用上错误的delete形式。
//云风评注:[ ]和vector是C++混乱的根源之一。如果你决定使用STL或template风格的C++,那么尽可能避免使用[ ],而不要去纠结哪个效率更高。
请注意:
为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。
Effective C++读书笔记之十三:以对象管理资源