条款13:以对象管理资源
Use objects to manage resources.
RCSP
对于auto_ptr,它的替代方案是:
- 引用计数型智慧指针(reference-counting smart pointer,RCSP)
所谓的RCSP,也是一个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它的时候自动删除该资源。
因此,RCSP所听的行为类似于垃圾回收(garbage collection),不同之处在于RCSP**无法打破环状引用(cycles of references,例如两个其实已经没有被使用的对象彼此互指,因而呈现出它们好像还处于“被引用”的状态)。**
TR1的tr1::shared_ptr
就是一个RCSP,因此可以这样构造f函数:
void f()
{
...
std::tr1::shared_ptr<Investment> pInv(createInvestment()); //调用factory函数,使用pInv
... //经由shared_ptr析构函数会自动删除pInv
}
这段代码,和auto_ptr的版本几乎一致,但是对于shared_ptr而言,复制操作就正常了许多:
void f()
{
...
std::tr1::shared_ptr<Investment> pInv1(createInvestment()); //pInv1指向createInvestment返回物
std::tr1::shared_ptr<Investment> pInv2(pInv1); //(copy构造)pInv1和pInv2指向同一个对象
pInv1 = pInv2; //(copy assignment)同上,pInv1和pInv2指向同一个对象
...
} //pInv1和pInv2都被销毁,它们所指的对象也被自动销毁了
因此,由于tr1::shared_ptr的复制行为“属于正常”行为,因此它们可以被用于STL容器以及其他的“因auto_ptr的非正常赋值行为而产生不适用”的情景中。
对于auto_ptr和tr1::shared_ptr而言,二者在析构函数内实现的,都是delete而非delete[ ]动作。因此,这就意味着:
- 不要在动态分配而得的array上使用auto_ptr或者tr1::shared_ptr。
例如,以下代码就是错误的:
str::auto_ptr<std::string> aps(new std::string[10]);//错误!使用了错误的delete
std::tr1::shared_ptr<int> spi(new int[1024]);//同样的错误
对此,并不存在特别为C++动态分配数组而设计的类似于auto_ptr或者tr1::shared_ptr这类东西,因为vector和string几乎总是可以取代动态分配而得到的数组。
另外,如果打算手工释放资源(例如使用delete而非使用一个资源管理类(resource-managing class)),这样做是很容易发生错误的。设计这样的资源管理类,需要注意很多的细节,这些内容会在条款14和15中讲到。
关于createInvestment,它所返回的是“未加工的指针(raw pointer)”,这对与资源泄漏是一个极大的隐患,因为调用者极易在这个指针身上忘记调用delete。即使使用了这一类的智能指针来执行这种delete,也必首先记的将createInvestment的返回值存储在智能指针对象内。
最后: