为防止资源泄露,请使用RAII对象,它们的构造函数中获得资源并在析构函数中释放资源。
假设一个用来塑模投资行为(股票,证券等)的程序库,其中各式各样的投资类型继承自一个root class Investment。
class Investment{...};
Investment* createInvestment(); //工厂函数,返回指针指向Investment继承体系的动态分配对象。调用者有责任删除它。
void f()
{
Investment* pInv = createInvestment();
...
delete pInv;
}
如果...区域中抛出异常、含有return语句 或者delete语句位于循环中,循环由于continue或者goto过早退出的情况下,都不能delete。
不仅是投资对象的内存被泄露,投资对象所包含的任何资源都被泄露。
为了确保createInvestment返回的资源总是被释放,把资源放进对象内,可以来c++的析构函数自动调用机制确保资源被释放。
(1)aoto_prt-》智能指针 其析构函数自动对其所指对象调用delete。
示例:
void f()
{
std::auto_ptr<Investment> pInv( createInvestment());
...
}
※获得资源后立刻放进管理对象内。
“以对象管理资源”的 行为常被称为“资源取得时机便是初始化时机 RAII”
※管理对象运用析构函数确保资源被释放。
不论控制流如何离开区块,一旦对象被销毁(例如对象离开作用域)其析构函数自然会被调释放资源。
注:
①别让多个auto_ptr指向同一个对象(防止对象被删除多次);
②若通过copying函数复制auto_ptr,会变成null,而复制所得的指针将取得资源的唯一拥有权。
以上2条意味着auto_ptr并非管理动态分配资源的神兵利器。举个例子:STL容器要求其元素正常复制,因此这些容器容不得auto_ptr。
(2)auto_ptr的替代方案:RCSP 引用计数型智慧指针 reference-counting smart pointer
RCSP也是个智能指针,持续跟踪共有多少对象指向某笔资源,并在无人指向它时自动释放该资源。(类似垃圾回收)
不同的是RCSPs无法打破环状引用(例如两个其实已经没被使用的对象彼此互指)。
例:TR1的 tr1::shared_ptr
void f()
{
...
std::tr1::shared_ptr<Investment> pInv( createInvestment());//shared_ptr的复制行为比auto_ptr正常
...
}
由于auto_ptr和shared_ptr两者都在其析构函数内做delete而不是delete[]动作,意味着动态分配而得的array身上使用auto_ptr和shared_ptr是个馊主意。
尽管如此,仍能通过编译。
std::auto_ptr<std::string> aps(new std::string[10]); //会用上错误的delete形式
std::tr1::shares_ptr<int> spi(new int[1024]);
拥有针对数组而设计,类似auto_ptr和shared_ptr的请参考:boost::scoped_array和boost::shares_array