· 管理对象使用它们的析构函数确保资源被释放。因为当一个对象被销毁时(例如,当一个对象离开其活动范围)会自动调用析构函数,无论控制流程是怎样离开一个块的,资源都会被正确释放。如果释放资源的动作会引起异常抛出,事情就会变得棘手。
当一个auto_ptr 被销毁的时候,会自动删除它所指向的东西,所以不要让超过一个的auto_ptr 指向同一个对象。如果发生了这种事情,那个对象就会被删除超过一次,而且会让你的程序进入不明确行为。为了防止这个问题,auto_ptrs 具有不同寻常的特性:拷贝它们(通过拷贝构造函数或者拷贝赋值运算符)就会将它们置为null,而复制所得的指针将取得资源的唯一拥有权!
std::auto_ptr
// pInv1指向createInvestment 返回物
std::auto_ptr
// 现在pInv2指向对象,pInv1被设为null
pInv1 = pInv2; // 现在pInv1指向对象,pInv2被设为null
受auto_ptrs 管理的资源必须绝对没有超过一个以上的auto_ptr 同时指向它,这也就意味着auto_ptrs 不是管理所有动态分配资源的最好方法。例如,STL 容器要求其元素发挥正常的复制行为,因此这些容器容不得auto_ptrs。
auto_ptrs的替代方案是引用计数型智能指针(reference-counting smart pointer, RCSP)。RCSP能持续跟踪有多少对象指向一个特定的资源,并能够在不再有任何东西指向那个资源的时候删除它。就这一点而论,RCSP 提供的行为类似于垃圾收集(garbage collection)。不同的是,RCSP 不能打破循环引用(例如,两个没有其它使用者的对象互相指向对方)。TR1 的tr1::shared_ptr就是个RCSP:
void f()
{
...
std::tr1::shared_ptr
// 调用factory 函数
... // 使用pInv一如既往
} // 经由shared_ptr析构函数自动删除pInv
void f()
{
...
std::tr1::shared_ptr
// pInv指向createInvestment对象
std::tr1::shared_ptr
//pInv1和pInv2指向同一个对象
pInv1= pInv2; // 同上,无任何改变
...
} // pInv1和pInv2被销毁,它们所指的对象也就被自动销毁
因为拷贝tr1::shared_ptrs 的行为“符合预期”,它们能被用于STL 容器以及其它和auto_ptr 的非正统的拷贝行为不相容的环境中。auto_ptr 和tr1::shared_ptr 都在它们的析构函数中使用delete,而不是delete []。这就意味着将auto_ptr 或tr1::shared_ptr 用于动态分配的数组是个馊主意。
C++ 中没有可用于动态分配数组的类似auto_ptr 或tr1::shared_ptr 这样的东西,甚至在TR1 中也没有。那是因为vector 和string 几乎总是能代替动态分配数组。你也可以去看看Boost,boost::scoped_array 和boost::shared_array 两个类提供了你在寻找的行为。
如果你手动释放资源(例如,使用delete,而不使用资源管理类),你就是在自找麻烦。像auto_ptr 和tr1::shared_ptr 这样的预制的资源管理类通常会使本条款的建议变得容易,但有时你所使用的资源是目前这些预制的类无法妥善管理的,你就需要精心打造自己的资源管理类。最后必须指出createInvestment 返回的“未加工指针”(raw pointer)是资源泄漏的请帖,因为调用者极易忘记在他们取回来的指针上调用delete。(即使他们使用一个auto_ptr 或tr1::shared_ptr 来完成delete,他们仍然必须记住将createInvestment 的返回值存储到智能指针对象中)。
· 为了防止资源泄漏,使用RAII 对象,在RAII 对象的构造函数中获得资源并在析构函数中释放它们。
· 两个通用的RAII 是tr1::shared_ptr 和auto_ptr。前者通常是更好的选择,因为其拷贝行为比较直观。若选择auto_ptr,复制动作会使被复制物指向null。
摘自 pandawuwyj的专栏