问题聚焦:

    上一条款所告诉我们的智能指针,只适合与在堆中的资源,而并非所有资源都是在堆中的。
    这时候,我们可能需要建立自己的资源管理类,那么建立自己的资源管理类时,需要注意什么呢?。
在详述这一章的主题之前,先回忆一下上一节所提到的一个名词——RAII(Resource Acquisition Is Initialization)
含义就是:资源取得时机便是初始化时机。
如果上一节对这个观念的理解还不是很深的话,那么下面这个例子可以让你更好地理解。

Demo 假设我们使用C API函数处理类型为Mutex的互斥器对象,共有lock和unlock两函数可用。
void lock(Mutex* pm);
void unlock(Mutex* pm);

为了确保不会忘记将一个被锁住的Mutex解锁,你可能会希望简历一个class用来管理锁。
这样的class的基本结构由RAII守则支配,也就是在“资源构造期间获得,在析构期间释放”
class Lock {
public:
explicit Lock(Mutex* pm) : mutexPtr(pm)
{ lock(mutexPtr); } // 获得资源
~Lock()
{ unlock(mutexPtr); } // 释放资源
}; // 客户对Lock的正确用法符合RAII方式
Mutex m; // 定义你需要的互斥器
....
{ // 建立一个区块用来定义critical section
Lock ml(&m); // 锁定互斥器
......
} // 在区块最末尾,自动接触互斥器锁定

上面的用法自然没有什么问题,那么问题是什么呢?——如果Lock对象被复制,会发生什么事呢?就像下面这样:
Lock ml1(&m);
Lock ml2(ml1);


一般化这个问题就是:当一个RAII对象被复制时, 会发生什么事情呢?
大多数情况下,有两种解决方法:
1 禁止复制:复制动作对RAII class并不合理。如果阻止复制操作,可以转到:Effective
C++(6) 如何拒绝编译器的自动生成函数
2 对底层资源祭出“引用计数法:
    通常,只要内含一个tr::shared_ptr成员变量,就可以实现引用技术。代码是下面这个样子的:
    class Lock {
public:
explicit Lock(Mutex* pm) : mutexPtr(pm, unlock)
{
lock(mutexPtr.get());
}
private:
std::tr1LLshared_ptr<Mutex> mutexPtr;
};

需要注意的一点是:tr1::shared_ptr的缺省行为是“当引用次数为0时,删除其所指对象”,或许这并不是我们想要的行为。幸运的是,tr1::shared_ptr并不是只能删除对象,而是允许指定我们想要的动作,只需要在第二个参数上传递一个对象或函数对象,当引用次数为0时,便被调用。
在本例中,传递的就是解锁函数,而不是删除所指对象。
遇到RAII的复制动作时,我们还可以有别的处理方式:
1 复制底部资源
    复制资源管理对象时,同时也可以复制其所包含的资源,因此进行的应该是“深拷贝”。
    例如:当一个对象包含一个指针指向一块堆内存时,复制这个对象,同时其指针和指向的内存都会被复制出一个复件。
2 转移底部资源的拥有权
    在某些场合下,你可能希望确保永远只有一个RAII对象指向一个未加工的资源,就像auto_ptr的复制行为。详见: Effective
C++(13) 用对象管理资源
小结:
  • 复制RAII对象必须一并复制它所管理的资源,所以资源的拷贝行为决定RAII对象的拷贝行为
  • 一般的复制行为是:阻止拷贝行为,使用引用计数法(tr1::shared_ptr)
参考资料:
《Effective C++ 3rd》

Effective C++(14) 在资源管理类中小心copying行为的更多相关文章

  1. [Effective C++ --014]在资源管理类中小心copying行为

    第一节 <背景> 条款13中讲到“资源取得的时机便是初始化时机”并由此引出“以对象管理资源”的概念.通常情况下使用std中的auto_ptr(智能指针)和tr1::shared_ptr(引 ...

  2. Effective C++ -----条款14: 在资源管理类中小心copying行为

    复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 普遍而常见的RAII class copying行为是:抑制copying(使用私有继承 ...

  3. effective条款15,在资源管理类中小心copying行为

    class A { private: int *p; void lock(){ cout << p << "is lock" << endl; ...

  4. 【14】在资源管理类中小心copying行为

    1.为什么要使用资源管理类? 资源管理类的思路就是,栈上的对象,封装堆上分配的资源,确保一定会释放资源.auto_ptr和shared_ptr就是资源管理类,行为上像指针. 2.auto_ptr和sh ...

  5. EC笔记:第三部分:14、在资源管理类中小心Copying行为

    场景 上一节实现了智能指针,其中的拷贝构造函数和赋值运算符是通过增加/减少指针的引用计数来操作的.但是如果是管理一个独占资源呢?我们希望在一个资源使用时被锁定,在使用完毕后被释放. #include ...

  6. 条款14:在资源管理类中小心copying行为

    请牢记: 1.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 2.普遍常见的RAII class copying行为是:抑制copyin ...

  7. Effective C++ 条款13/14 以对象管理资源 || 在资源管理类中小心拷贝行为

    三.资源管理       资源就是一旦你使用了它,将来不用的时候必须归还系统.C++中最常用的资源就是动态内存分配.其实,资源还有 文件描述符.互斥器.图形界面中的字形.画刷.数据库连接.socket ...

  8. Effective C++(15) 在资源管理类中提供对原始资源的访问

      问题聚焦:     资源管理类是为了对抗资源泄露.     如果一些函数需要访问原始资源,资源管理类应该怎么做呢?        关于资源管理的概念总是显得那么的高大上,其实只是抽象一点. 下面用 ...

  9. [Effective C++ --015]在资源管理类中提供对原始资源的访问

    引言 资源管理类是防止资源泄漏的有力武器,但是许多APIs直接指涉资源,除非你发誓永不使用这样的APIs,否则只得绕过资源管理对象(resource-managing objects)直接访问原始资源 ...

随机推荐

  1. java回调机制及其实现(转)

    1. 什么是回调函数 回调函数,顾名思义,用于回调的函数.回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数.回调函数是一个工作流的一部分,由工作流来决定函数的调用(回调)时机.回调 ...

  2. android static达到Service与Activity于Handler沟通

    供static理解力,仅适用于static理解力,不喜勿喷 第一种方式:离Service中获取Activity的static变量,调用该静态变量的getHandler()获取Handler进行发送消息 ...

  3. JavaScript学习之获取URL参数

    最近看了几道面试题,其中有一道就是关于写一个方法来获取浏览器地址栏URL查询部分的字段内容.虽然之前看过相关的东西,但感觉有点模糊,所以就又全面的学习一遍,谨以此文记之! 准备知识 在JavaScri ...

  4. Oracle 修改字符集

    出现ORA-12899,是字符集引起的,中文在UTF-8中占3个字节,ZHS16GBK中占2个字节,而源dmp文件字符集是ZHS16GBK库里倒出来的数据,现在要导入到目标字符集为UTF-8的库里,所 ...

  5. 大数据系列修炼-Scala课程04

    Scala中继承实现:超类的构造.字段重写.方法重写 关于超类的构建:超类可以在子类没有位置的限制,可以在子类中调用父类的方法 类中字段重写:在重写字段前面加一个override就可以重新赋值 类中方 ...

  6. 《代码的第一行——Android》封面诞生

    <代码的第一行--Android>已经上市近一个月,现在的情况是相当不错的销售,也特别感谢众多朋友的支持. 其实一本好书,假设你想卖.除了给予外力所要求的内容.封面设计是至关重要的,这本书 ...

  7. 经典算法题每日演练——第七题 KMP算法

    原文:经典算法题每日演练--第七题 KMP算法 在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树 ...

  8. linux_vim_最佳快捷键

    如何使用vi文本编辑器     vi由比尔·乔伊(Bill Joy)撰写,所有UNIX like均默认安装此文本编辑器.详细简介请点击维基中文. 1.首先复制一个文件到/tmp目录(本例中为复制根目录 ...

  9. [CLR via C#]1.6 Framework类库~1.9与非托管代码的互操作性

    原文:[CLR via C#]1.6 Framework类库~1.9与非托管代码的互操作性 1.6 Framework类库 1. .NET Framework中包含了Framework类库(Frame ...

  10. 使用JFinal框架中Validator

    Validator是JFinal框架中的校验组件,在Validator类中提供了我们经常使用的校验方法,而Validator本身实现了Interceptor接口,所以Validator也相当于一个拦截 ...