Effective C++ 笔记(3)
第三部分: 资源管理
条款13: 以对象管理资源
void f() {
Investment *pInv = createInvestment();
...
delete pInv;
}
当...区域提前return,或者抛出异常,delete语句就可能不被调用.
为了确保createInvestment返回的资源总是被释放, 我们需要将资源放进对象内,当控制流离开f,该对象的析构函数会自动释放那些资源。
许多资源被动态分配于heap内而后用于单一区块或者函数内。它们应在控制流离开那个区块或函数时被释放。标准程序库提供的auto_ptr正是针对这种形势设计的。
auto_ptr是个类指针对象,其析构函数自动对其所指对象调用delete。
void f(){
std::auto_ptr<Investment> pInv(createInvestment());
...
} //经由auto_ptr的析构函数自动删除pInv
千万注意别让多个auto_ptr指向同一对象,否则对象会被删除一次以上。为了预防这个问题auto_ptr有一个不寻常的性质:若通过copy构造函数或者copy assignment操作符复制它们,它们会变成null,而复制所得的指针将取得资源的唯一使用权。
auto_ptr的替代方案是引用计数型智慧指针(RCSP),其持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源(但是它无法打破环装引用)。
shared_ptr就是个RCSP
值得注意的是C++11提出了unique_ptr替代auto_ptr,其更加安全。
(1)unique_ptr不允许复制,除非右值是个临时右值
(2)unique_ptr相比于auto_ptr和shared_ptr提供了可用于数组的变体。
请记住:
- 为了防止资源泄露,请使用RAII对象,它们在构造函数中获得资源,在析构函数中释放资源
条款14: 在资源管理类中小心coping行为
请记住:
- 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定了RAII对象的copying行为
- 普遍而常见的RAII class coping行为是:抑制copying、施行引用计数法。不过其他行为也都可能被实现。
条款15:在资源管理类中提供对原始资源的访问
请记住:
- APIs往往要求访问原始资源,所以每一个RAII class应该提供一个取得所管理之资源的方法
- 对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,隐式转换对客户比较方便
条款16: 成对使用new和delete时要采取相同形式
请记住:
- 如果你在new表达式中使用[],必须在相应的delete表达式中也使用[],如果你在new表达式中不使用[],必须在相应的delete表达式中也不使用[]
条款17:以独立语句将newed对象置入智能指针
例如
processWidget(std::shared_ptr<Widget>(new Widget), priority());
当编译器生成这样的操作序列
1、执行new Widget
2、调用priority()
3、调用shared_ptr构造函数
如果在第二步中发生了异常,就产生了资源泄露
因此应写成分离语句
std::shared_ptr<Widget>pw(new Widget);
processWidget(pw, priority())
请记住:
以独立语句将newed对象存储于(置入)智能指针内,如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄露。