上节我们介绍了一个观念:资源取得时机便是初始化时机(Resource Acquisition Is Initialization RAII),同时介绍了两个程序库提供的管现指针的资尖管理类auto_ptr和trl::shared_ptr。然而并不是所有的资源都是指针,所以有时我们要设计自己的资源管理类。
设计一个资源管理类:
假如我们用C APT处理类型为Mutex的互斥器对象,共有两个函数可用:
void lock(Mutex * pm); //锁定pm所指的互斥器
void unlock(Mutex * pm); //将互斥器解除锁定
为了不忘记将一个被锁定的Mutex解除,这时就需要自己设计一个资源管理类,这样的class的基本结构由RAII守则支配,也就是资源在构造期间获得,在析构期间释放:
class Lock {
public:
explicit Lock(Mutex *pm):mutexPtr(pm)
{ lock(mutexPtr); } //获得资源
~Lock() { unlock(mutexPtr); } //释放资源
private:
Mutex *mutexPtr;
};
这时你可以安全的使用这个资源了
Mutex m; //定义这个资源
....
{ //建立一个区块用来定义critical section
Lock m1(&m); //锁定互斥器
..... //执行critical section内的操作
} //在区块结束时,调用析构函数来解除互斥器锁定
现在面临的问题:
在一个RAII对象被复制,会发生什么事?针对下面的例子就是当有下面代码时会发生什么?
Lock m1(&m);
Lock m2(m1); //用m1来copy构造m2
主要有两种处理方法:
1) 禁止复制 在条款6中告诉你怎么做了:将copying操作符声明为private。
2) 对成员使用引用计数法(reference-count),即上节的智能计数指针。这种情况下拖后腿制RAII对象时,应该将资源的被引用数递增。可以使用trl::shared_ptr便是如此。不过它还有一个问题就是它的缺省行为是”当引用次数为0时删除其所指物“,我们希望的动作是解除锁定而不是删除,不过还好trl::shared_ptr允许改变缺省行为指定为我们自己的行为。例如:
class Lock {
public:
explicit Lock(Mutex *pm):mutexPtr(pm , unlock) //设定我们的解除行为unlock
{ lock(mutexPtr); } //获得资源
private:
std::trl::shared_ptr<Mutex> MutexPtr; //使用share_ptr来替换raw pointer
};
注意这个class不用声明析构函数,因为没有必要。因为class析构函数会自动调用其成员的析构函数。我们为成员指定了删除行为。
总结:
1) 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copyint行为
2) 普通而常见的RAII class copying 行为是:禁止copying,使用引用计数法,不过其他行为也都可能被实现
Effective C++读书笔记之在资源管理类中小心coping行为
最新推荐文章于 2025-03-15 19:00:00 发布