Chapter3
条款13:以对象管理资源
RAII
守则:资源在构造期间获得,在析构期间释放- 为防止资源泄露,使用
RAII
对象,它们在构造函数中获得资源并在析构函数中释放资源 - 两个常被使用的
RAII classes
分别是shared_ptr
和auto_ptr
。前者通常是较佳选择,因为其copy
行为比较直观。若选择auto_ptr
,复制动作会使它(被复制物)指向null
auto_ptr
和tr1::shared_ptr
两者都在其析构函数内做delete
而不是delete []
动作(若需执行delete []
需特别说明).同时tr1::shared_ptr
的缺省行为是"当引用次数未0时删除其所指物"(解决办法是自定义一个删除器)
shared_ptr<int> sp(new int[10],[](int *p){ delete p;});
unique_ptr<int[]> up(new int[10]);
up.release();
struct destination;
struct connection;
connection connect(destination*);
void disconnect(connection);
void f(destination &d){
connection c=connect(&d);
shared_ptr<connection> p(&c,end_connection);
}
条款14:在资源管理类中小心copying
行为
- 复制
RAII
对象必须一并复制它所管理的资源,所以资源的copying
行为决定RAII
对象的copying
行为 - 普通而常见的
RAII class copying
行为是:抑制copying
(比如unqiue_ptr
)、施行引用计数法(shared_ptr
)
条款15:在资源管理类中提供对原始资源的访问
APIs
往往要求访问原始资源,所以每一个RAII class
应该提供一个"取得其所管理之资源"的办法- 对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便(显式转换和隐式转换见下例)
class Font{
public:
...
FontHandle get() const { return f; }
...
};
class Font{
public:
...
operator FontHandle() const
{
return f;
}
...
};
条款16:成对使用new
和delete
时要采用相同形式
- 使用
new
时有两件事会发生:
- 内存被分配出来(通过名为
operator new
的函数) - 针对此内存会有一个(或更多)构造函数被调用
- 使用
delete
时也有两件事会发生:
- 针对此内存会有一个(或更多)析构函数被调用
- 内存被释放(通过名为
operator delete
的函数)
- 数组所用的内存通常还包括“数组大小”的记录,以便
delete
知道需要调用多少次析构函数 - 如果在
new
表达式中使用[]
,必须在相应的delete
表达式中也使用[]
。如果在new
表达式中不使用[]
,一定不要在相应的delete
表达式中使用[]
条款17:以独立语句将newed
对象置入智能指针
- 以独立语句将
newed
对象存储于智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄露.(见下例)
processWidget(std::tr1::shared_ptr<Widget>(new Widget),priority());
std::tr1::shared_ptr<Widget> pw(new Widget);
processWidget(pw,priority());