Item14:在资源管理类中小心 coping行为

0.概述

  • 复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。
  • 普遍而常见的 RAII class copying行为是:抑制copying、施行引用计数法(reference counting)。不过其他行为也都可能被实现。

1.举例(mutex互斥器)

假设处理Mutex互斥器对象,共有lock和unlock两函数可用。

void lock(Mutex *pm); //锁定pm所指的互斥器
void unlock(Mutex *pm); //将互斥器解除锁定

为确保绝不会忘记将一个被锁住的 Mutex解锁,建立1个class用来管理机锁。这样的class的基本结构由RAII守则支配,也就是“资源在构造期间获得,在析构期间释放”:;
 

class Lock{
    public:
        explicit Lock(Mutex* pm):mutexPtr(pm)
        {
            lock(mutexPtr);//获得资源
        }
        ~Lock(mutexPtr);//释放资源
    private:
        Mutex *mutexPtr;
};

对Lock的用法需要符合RAII方式:

Mutex m; //定义需要的互斥器
...
{ //建立区块定义critical section
    Lock m1(&m); //锁定互斥器
    ... //执行critical section内的动作
}//区块末尾自动解除互斥器锁定

2.Lock对象被复制会发生什么?

但是如果Lock对象被复制会发生什么?

Lock m1(&m); //锁定m
Lock m2(m1); //会发生啥?

一般会选择一下两种可能:

2.1 禁止复制

如果复制操作对RAII class不合理,就应该禁止。参考Item6:将copying操作声明为private,以Lock为例:

class Lock:private Uncopyable{
    public:
    ...
};

2.2 对底层资源祭出“引用计数法”(reference-count)

有时候我们希望保有资源,直到它的最后一个使用者(某对象)被销毁。这种情况下复制RAII对象时,应该将资源的“被引用数”递增。tr1::shared_ptr便是如此。通常只要含有一个tr1::shared_ptr成员变量,RAlI classes便可实现出reference-counting copying行为。如果Lock打算使用reference counting,可以将mutexPtr的类型从Mutex*改为tr1::shared_ptr<Mutex>。

然而!!tr1: :shared_ptr的缺省行为是“当引用次数为0时删除其所指物”,这不是我们想要的。当是使用Mutex时,我们想要做的释放动作是解除锁定而非删除。

但是tr1::shared_ptr允许指定“删除器”(deleter),这是一个当引用次数为0时会被调用的函数或函数对象(注:auto_ptr中不存在这种机制,它总是将指针删除)。删除器对于tr1::shared_ptr构造函数是一个可选的第二参数,代码如下:

class Lock{
    public:
        explicit Lock(Mutex* pm)//以某个Mutex初始化shared_ptr
         :mutexPtr(pm,unlock)//以unlock为删除器
        {
            lock(mutexPtr.get());
        }
    private:
        std::tr1::shared_ptr<Mutex> mutexPtr;//使用shared_ptr替换raw pointer
};

:不需要再声明析构函数。Item5:class析构函数(无论是编译器生成的,或用户自定的)会自动调用其non-static成员变量(本例为mutexPtr)的析构函数。而mutexPtr的析构函数会在互斥器的引用次数为0时自动调用tr1::shared_ptr的删除器(unlock)。

2.3 复制底部资源

有时候可以针对一份资源拥有其任意数量的复件(副本)。而需要“资源管理类”的唯一理由是,当你不再需要某个复件时确保它被释放。在此情况下复制资源管理对象,应该同时也复制其所包覆的资源。也就是说,复制资源管理对象时,进行的是“深度拷贝”。
某些标准字符串类型是由“指向heap内存”的指针构成(那内存被用来存放字符串的组成字符)。这种字符串对象内含一个指针指向一块heap 内存。当这样一个字符串对象被复制,不论指针或其所指内存都会被制作出一个复件。这样的字符串展现深度复制(deep copying〉行为。

2.4 转移底部资源的拥有权

某些罕见场合下可能希望确保永远只有一个RAII对象指向一个未加工资源(raw resource),即使RAII对象被复制依然如此。此时资源的拥有权会从被复制物转移到目标物。Item13:这是auto_ptr奉行的复制意义。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值