假设我们使用一个用来塑模投资行为的程序库,其中各式各样的投资类型继承自一个root class Investment:
class Investment{...}; //"投资类型",继承体系中的root class
假设这个程序库通过一个工厂函数提供我们特定的Investment对象:
Investment* createInvesment(); //返回指针,指向Investment继承体系内的动态分配对
//象
加入有个f函数调用了这个函数的返回对象并删除了它。
void f()
{
Investment* pInv = createInvestment(); //调用factory
...
delete pInv; //释放pInv所指对象
}
现在看来此处不会有问题。但是如果"..."区域有一个过早的return语句。如果这样的return语句执行起来,就不会触发delete语句。
为了确保createInvestment返回的资源总是被释放,我们需要将资源放进对象内,当离开函数f时,该对象的析构函数就会自动释放那些资源。
许多资源被动态分配于heap内而后被用于单一区域或函数内。它们应该被控制流离开那个区域或函数时被释放。标准程序库函数提供auto_ptr正是针对这种形式而设计。auto_ptr是个类指针对象,也就是所谓的智能指针。其析构函数自动调用其所指对象delete。
void f()
{
std::auto_ptr<Investment> pInv(createInvestment());//经由auto_ptr的析构函数自动删除pInv
}
“以对象管理资源”的两个关键想法:
(1) 获得资源后立刻放进管理对象内。
“以对象管理资源”的观念常常被称为“资源取得时机便是初始化时机”(Resource Acquiisition Is Initialzation;RAII)
(2)管理对象运用析构函数确保资源被释放。
由于auto_ptr被销毁时会自动删除它所指之物,所以不要让多个auto_ptr同时指向同一对象。否则,对象会被删除一次以上。为了预防这个问题。auto_ptrs有一个不同寻常的性质:若通过copy构造函数或copy_assignment操作符复制它们,它们会变成null,而复制的指针将取得资源的唯一拥有权。
std::auto_ptr<Investment> pInv1(createInvestment()); //pInv1指向createInvestment返回
std::auto_ptr<Investmnet> pInv2(pInv1); //现在pInv2指向对象,pInv1被设为null
pInv1 = pInv2; //现在pInv1指向对象,pInv2被设为null
auto_ptr的替代方案是“引用计数型智慧指针”(reference-counting smart pointer;RCSP)。所谓的RCSP也是个智能指针,持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除资源。
void f()
{
...
std::tr1::shared_ptr<Investment>
pInv(createInvestment); //调用factroy,经由shared_ptr析构函数自动删除pInv
}
这段代码看起来和auto_ptr的那个版本相同,但share_ptrs的复制行为正常多了:
void f()
{
...
std::tr1::shared_ptr<Invesment>
pInv1(createInvestment()); //pInv指向createInvestment返回物
std::tr1shared_ptr<Investment> pInv2(pInv1);//pInv1和pInv2指向同一个对象
pInv2(pInv1); // 同上,还是指向同一个对象
... //pInv1和pInv2被销毁,它们所指的对象也就被自动销毁
}
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]);
并没有针对C++动态分配数组而设计的类似auto_ptr或tr1::shared_ptr那样的东西。因为vector和string几乎总是可以取代动态分配而得的数组。
结论:
为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。
两个常被使用的RAII classes分别是tr1::shared_ptr和auto_ptr。前者通常是最佳选择,因为其copy行为比较直观。若选择auto_ptr,复制行为会使它(被复制物)指向null。