Effective C++ 条款13 以对象管理资源

条款13 : 以对象管理资源

所谓资源, 一旦用了它, 将来必须还给系统. 本条款及以后几项条款都致力于实现优秀的资源管理, 严守这些条款, 可以几乎消除资源管理问题.

本条款主要提出以对象管理资源的思想, 以及对std内置的auto_ptrsmart_prt的使用策略做了分析.

书中塑模了一个投资行为, 让我们看看资源该如何处理 :

1
2
3
4
5
6
7
8
9
10
class Investment { ... };  // 一个投资类

Investment* createInvestment(); // 这是一个工厂函数, 返回一个动态分配的对象, 这里为了简化刻意不写参数

void f()
{
Investment *pInv = createInvestment();
...
delete pInv;
}

如果没有资源管理对象, 我们正常行为是请求指针使用后再手动删除.

书中提出了”以对象管理资源”的两个关键想法 :

  • 获得资源后立即放进管理对象.
  • **管理对象运用析构函数确保资源被释放, **这样便可倚赖 C++ 的”析构函数自动调用机制“确保资源被释放.

这两个想法来源于一种资源管理观念 :

  • RAII (Resoure Acquisition Is Initialization) : 资源取得时机便是初始化时机 .

那么资源管理类该如何使用与实现呢 ? 不妨看看C++本身给我们提供的两个资源管理类(智能指针)吧.


auto_ptr

1
2
3
4
5
void f()
{
std::auto_ptr<Investment> pInv(createInvestment()); // 请求对象的同时直接存入auto_ptr中
...
}

这样我们可以一如既往地使用pInv, 当其离开作用域时, 会经由auto_ptr的析构函数自动删除pInv.

auto_ptr的特性 : 受auto_ptr管理的资源必须绝对没有一个以上的auto_ptr同时指向它.

也就是说auto_ptr保证独占指向的资源, 如果发生拷贝也会转交使用权, 这种特性使得其在需求共享内存的场面起不到作用, 于是也就有了我们接下来的shared_ptr.


shared_ptr

1
2
3
4
5
6
7
void f()
{
std::shared_ptr<Investment> pInv1(createInvestment());
...
std::tr1::shared_ptr<Investment> pInv2(pInv1); // 允许指向同一块内存
pInv1 = pInv2; // 允许赋值同时获得使用权
}

share_ptr是”引用计数型智能指针“, 其自己内部维护了一个计数器, 用于记录指向同一块资源的指针有多少, 当发生拷贝和赋值时都会使计数器 + 1, 当有指向其的指针离开作用域时都会使计数器 - 1, 当计数器为0时才自动触发真正的析构.


请注意 : auto_ptrshared_ptr的析构函数内部调用的都是 delete, 而非 delete[], 虽然我们可以 new [], 但是这样new出来的指针就请不要存入智能指针了.

1
std::shared_ptr<int> spi(new int[100]); // 这样是错误的!

至于为什么没有delete[]版本的, 那是因为vectorstring几乎总是可以取代动态分配而得的数组, 所以没必要.


以上专门描述了auto_ptrshared_ptr, 但是本条款并不专门针对它们, 而是在强调”以对象管理资源“的重要性, 有时候我们要使用的资源也许是这些预制式classes无法妥善管理的, 就需要我们有自己制作资源管理类的能力了, 至于其中要考虑的细节, 在接下来的条款14, 15中会提及.


请记住 :

  • 为防止资源泄露, 请使用RAII对象, 它们在构造函数中获得资源并在析构函数中释放资源.
  • 优先使用shared_ptr, auto_ptr次之, 如果效果无法令你满意, 请自己制作资源管理类.

by 天目中云


Effective C++ 条款13 以对象管理资源
http://example.com/2024/11/30/[Effective C++]条款13 以对象管理资源/
作者
天目中云
发布于
2024年11月30日
许可协议