请牢记:

1、复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。

2、普遍常见的RAII class copying行为是:抑制copying、施行引用计数法。不过其他行为也可能被实现。

auto_ptr和tr1::shared_ptr的观念表现在heap_based资源上。然而并非所有资源都是heap_based,对于非heap_based资源而言,需要建立自己的资源管理类。

假设我们使用C API函数出来类型为Mutex的互斥器对象(mutex objects),共有lock和unlock两个函数。

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

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

  1. class Lock
  2. {
  3. public:
  4. explicit Lock(Mutex* pm)
  5. : mutexPtr(pm)
  6. {
  7. Lock(mutexPtr); //获得资源
  8. }
  9. ~Lock()
  10. {
  11. unlock(mutexPtr); //释放资源
  12. }
  13. private:
  14. Mutex *mutexPtr;
  15. };

客户对Lock的用法符合RAII方式:

  1. Mutex m;
  2. ...
  3. {
  4. Lock ml(&m); //锁定互斥器
  5. ...
  6. } //在区块末尾,自动解除互斥器锁定

如果此时Lock对象被复制:

  1. Lock ml1(&m); //锁定m
  2. Lock ml2(ml1); //将ml1复制到ml2上,会发生什么?

可能有以下两种选择:

禁止复制:许多时候允许RAII对象复制并不合理:

如果没有按需要定义复制构造函数和赋值操作符,那么得到的结果通常是:非内存资源被创建一次,释放多次。
禁止方式:将copying操作声明为private。

  1. class Lock : private Uncopyable  //禁止复制。见条款6
    {
  2. public:
  3. ...            //如前
  4. };

如果需要复制,重新定义复制构造函数和赋值操作符是必须的。
怎么写它们是一个问题,具体的方案依赖于实际的需要,可以使用深拷贝,也可以使用类似于 shared_ptr 的引用计数机制,或者传递所有权。

对底层资源采用引用计数法

复制RAII对象时,将该资源的“被引用数”递增。例:shared_ptr。

shared_ptr的缺省行为是“当引用次数为0时删除所指物”,但是上面的例子我们想要的动作是解除lock而非删除。
好在shared_ptr允许指定“删除器”:

  1. class Lock
  2. {
  3. public:
  4. explicit Lock(Mutex* pm):mutexPtr(pm,unlock) //以某个mutex初始化shared_ptr,并以unlock函数为删除器
  5. {lock(mutexPtr.get());}           //条款15
  6.  
  7. ~Lock(){unlock(mutexPtr);}           //释放资源
  8. private:
  9. std::tr1::shared_ptr<Mutex> mutexPtr;
  10. };

深度拷贝:
某些标准字符串类型是“指向heap内存”之指针构成。这样的字符串对象被复制,不论指针或其所指内存都会被制作出一个复件。这样的字符串展现深度复制行为。

转移底部资源的拥有权:

auto_ptr奉行的复制意义:RAII对象被复制,资源的拥有权从被复制物转移到目标物。

条款14:在资源管理类中小心copying行为的更多相关文章

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

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

  2. Effective C++(14) 在资源管理类中小心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. [Effective C++ --014]在资源管理类中小心copying行为

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

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

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

  8. Effective C++ 条款15、16 在资源管理类中提供对原始资源的访问||成对使用new 与 delete要采取相同形式

    1.在资源管理类中提供对原始资源的访问     前几个条款很棒,它们是对抗资源泄露的壁垒,但很多APIs直接指向 资源,这个时候,我们需要直接访问原始资源.     这里,有两种方法解决上述问题,我们 ...

  9. 读书笔记 effective c++ Item 15 在资源管理类中提供对原生(raw)资源的访问

    1.为什么需要访问资源管理类中的原生资源  资源管理类是很奇妙的.它们是防止资源泄漏的堡垒,没有资源泄漏发生是设计良好的系统的一个基本特征.在一个完美的世界中,你需要依赖这样的类来同资源进行交互,绝不 ...

随机推荐

  1. React为啥很多类里的标签上事件处理函数要用bind(this)

    render() { return ( <div> <p onClick={this.clickHandler.bind(this)}>vz</p> </di ...

  2. C#7

    C#7 阅读目录 out变量 元组(Tuples) 模式匹配(Pattern matching) 本地引用和返回(Ref locals and returns) 本地函数(Local function ...

  3. Android--数据持久化存储概述

    Android数据持久化存储共有四种方式,分别是文件存储.SharedPreferences.Sqlite数据库和ContentProvider.在本篇幅中只介绍前面三种存储方式,因为ContentP ...

  4. WPF中利用RadialGradient模拟放大镜效果

    原文:WPF中利用RadialGradient模拟放大镜效果 --------------------------------------------------------------------- ...

  5. QT中窗口刷新事件的学习总结(viewport, paintEvent, repaint, update, erase, updatesEnabled)

    一.主要理解一下几个方法和属性: 1.QWidget * QScrollView::viewport () const 2.void QWidget::paintEvent ( QPaintEvent ...

  6. ISO/IEC 27001 信息安全管理体系认证

    一. 信息安全管理体系标准业务介绍 1. 背景介绍 信息作为组织的重要资产,需要得到妥善保护.但随着信息技术的高速发展,特别是Internet的问世及网上交易的启用,许多信息安全的问题也纷纷出现:系统 ...

  7. 开源mvcpager分页控件分页实例

    最近MVC需要用到分页,然后在网上找了一圈,发现一个很好用的分页控件,在此要感谢作者的辛勤劳动. 下载Pager 这个分页控件也有Asp.net的支持,需要的去看看作者的主页 webdiyer 先看看 ...

  8. bigdata_ Kafka集群模式部署

    环境:kafka 0.8.1.1 基本概念 Kafka维护按类区分的消息,称为主题(topic) 生产者(producer)向kafka的主题发布消息 消费者(consumer)向主题注册,并且接收发 ...

  9. hdu 4035 可能性DP 成都网络游戏

    http://acm.hdu.edu.cn/showproblem.php?pid=4035 获得: 1.首先推断是不是树.事实上,所有的感觉身影,既看边数==算-1是不成立 2.有时候,我告诉孩子来 ...

  10. WPF的Timer控件的使用

    原文:WPF的Timer控件的使用 通过System.Threaing.Timer控件来实现“初始加载页面时为DataGrid的模版列赋初始值” System.Threaing.Timer的用法: 步 ...