目录
1.前言
并非所有资源都是heap-based,对那类资源而言,像auto_ptr和share_ptr这类指针往往不适合作为资源管理者(resource handles)。所有,需要建立自己的资源管理类。
假如使用C中的API函数处理类型为Mutex的互斥器对象(关于mutex的知识:【线程(二)】——互斥量的详细解析_线程互斥量-CSDN博客),共有lock和unlock俩函数可用:
void lock(Mutex* pm);//锁定pm所指向的互斥器
void unlock(Mutex* pm);//将互斥器解锁
为确保绝不会忘记将一个被锁住的Mutex解锁,需要建立一个class类来管理机锁。
2.建立class管理锁
为了实现上面的目的,该类的基本结构由RAII守则支撑,既“资源在构造期间获得,在析构期间释放”:
class Lock{
public:
explict Lock(Mutex* pm):mutexPtr(pm)
{
lock(mutexPtr);//上锁
}
~Lock()
{
unlock(mutexPtr);//解锁
}
private:
Mutex* mutexPtr;
}
客户对Lock的用法符合RAII方式:
Mutex m;//定义所需的互斥器
...
{//建立一个区块用来定义critical section
Lock ml(&m);//锁定互斥器
...//执行critical section内的操作
} //在区块末尾,自动解除互斥器的锁定
3.若出现复制现象,会出现什么事?
倘若:
Lock ml1(&m);//锁定m
Lock ml2(ml1);调用默认的拷贝构造函数,将ml1复制到ml2上,这会发生什么事?
这个一般化问题是每个人都会用到的,即:“当RAII对象被复制,会发生什么事“,大多数会选择两种可能:
1.禁止复制
许多时候允许RAII对象被复制并不合理,对一个像Lock这样是存在这种现场的。如果复制操作对RAII Class并不合理,应该禁止复制。具体操作为将copying操作声明为private(条款6:若不想使用编译器自动生成的函数,就该明确拒绝-CSDN博客)。对Lock而言看起来是这样的:
class Lock:private Uncopyable//禁止复制,可见条款6
{
public:
...
}
2.对底层资源使用”引用计数法“
引入share_ptr,在复制RAII对象时,应该将资源的”被引用数“递增,直到它的最后一个使用者被销毁。
一般只要类里面存在trl::share_ptr成员变量,就可实现引用复制操作(reference-counting copy),share_ptr所引用的次数为0时删除其所指的对象,但当用在Mutex时候,我们想要的操作是释放锁定而非删除。幸运的是trl::share_ptr也允许指定所谓的”删除器“,那是一个函数或者函数对象,当引用次数为0时候便被调用(此机能不存在于auto_ptr-它总会将其指针删除)。注意的是删除器对trl::share_ptr构造函数而言是可有可无的第二个参数,所有代码如下:
class Lock{
public:
explict Lock(Mutex* pm)::mutexPtr(pm,unlock)//以Mutex初始化share_ptr
{
lock(mutexPtr.get());见条款15
}
private:
std::trl::shared_ptr<Mutex> mutexPtr;//使用share_ptr替换raw pointer
}
这里Lock class为什么不再声明析构函数,见条款5(条款5:了解C++默默编写并调用哪些函数-CSDN博客)。而mutexPtr的析构函数会在引用次数为0时候调用trl::share_ptr的删除器(本例为unlock)
3.复制资源管理对象时,进行深拷贝
4.转移底部资源的拥有权,比如auto_ptr的操作