Item 14: Think carefully about copying behavior in resource-managing classes.
设计一个 RAII
对象:
1 | class Lock { |
客户对Lock
的使用:
1 | Mutex m; |
当一个 RAII
对象被复制,会发生什么事? 不确定?
1 | Lock ml1(&m); |
记住资源管理对象的拷贝行为取决于资源本身的拷贝行为,同时资源管理对象也可以根据业务需要来决定自己的拷贝行为。一般有如下四种方式:
禁止复制。参考若不想使用编译器自动生成的函数,就该明确拒绝。对Lock而言看起来是这样:
1
2
3
4class Lock : private Uncopyable {
public:
...
}引用计数,采用
shared_ptr
的逻辑。shared_ptr
构造函数提供了第二个参数deleter
,当引用计数到0
时被调用。 所以Lock
可以通过聚合一个shared_ptr
成员来实现引用计数:1
2
3
4
5
6
7
8class Lock{
public:
explicit Lock(Mutex *pm): mutexPtr(pm, unlock){
lock(mutexPtr.get());
}
private:
std::shared_ptr<Mutex> mutexPtr; //shared_ptr替换 raw pointer
};Lock
的析构会引起mutexPtr
的析构,而mutexPtr
计数到0时unlock(mutexPtr.get())
会被调用。拷贝底部资源。复制资源管理对象时,进行的是深拷贝。比如
string
的行为:内存存有指向对空间的指针,当它被复制时会复制那片空间。转移底部资源的拥有权。
auto_ptr
就是这样做的,把资源移交给另一个资源管理对象,自己的资源置空。