[Effective C++ --014]在资源管理类中小心copying行为
第一节 <背景>
条款13中讲到“资源取得的时机便是初始化时机”并由此引出“以对象管理资源”的概念。通常情况下使用std中的auto_ptr(智能指针)和tr1::shared_ptr(引数智能指针)作为管理资源的对象。
事实上,这种管理方法十分有效。但是,auto_ptr和tr1::shared_ptr只能管理基于堆(heap-based)的资源,而非heap-based的资源却往往不适合。
因此,有的时候你需要建立自己的资源管理类。本文介绍的内容是在你建立自己的资源管理类时应该注意的事项。
第二节 <正文>
我们知道在C API中处理Mutex的互斥对象,有lock何unlock两个函数可用:
void lock(Mutex* pm); // 锁定pm指向的互斥量
void unlock(Mutex* pm); // pm指向的互斥量解锁
假设我们写了Lock类来管理锁。
class Mutex{
public:
Mutex():Count(){}
public:
int Count;
};
void lock(Mutex* pm){pm->Count++;}
void unlock(Mutex* pm){pm->Count--;}
class Lock
{
public:
explicit Lock(Mutex* pm):mutexPtr(pm)
{lock(mutexPtr);} // 将mutexPtr指向的互斥变量加锁
~Lock(){unlock(mutexPtr);} // 将mutexPtr指向的互斥变量解锁
private :
Mutex * mutexPtr;
};
上面代码满足RAII(Resource Acquisition is Initialization)原则即,资源在获取时既是初始化时,失去时既是清理时。
想象下面的场景时,程序的输出结果是什么。
Mutex m;
cout << "Mutex is " << m.Count << endl;
Lock m1(&m);
cout << "Mutex is " << m.Count << endl;
Lock m2(m1);
cout << "Mutex is " << m.Count << endl;
m1.~Lock();
cout << "Mutex is " << m.Count << endl;
输出结果为:
Mutex is
Mutex is
Mutex is
Mutex is
这是为什么呢?前两个0和1输出无可厚非,第三个的输出为拿m1作为实例对象去赋值给m2,操作对象为m1,不会直接影响m;第四个互斥量m的管理者m1被销毁了,那么m也就被解锁了。
在上面的例子中,m的值不断被变更,显然,这种资源的管理的方式是不合理的。
可能的解决方法:
1.禁止复制。禁止复制的做法具体的可参照条款6的说明。
class UnCopyable {
public:
UnCopyable(){}
private:
UnCopyable(const UnCopyable& ths) {
}
};
class Lock:private UnCopyable {
...
}
2.使用引用计数智能指针:tr1::shared_ptr。
从条款13我们已经知道引用计数智能指针会跟踪使用该资源的所有对象数,计数为0时,资源会被删除。注意,这里删除互斥量m不是我们所期待的,我们期待是解锁互斥量
幸运的是tr1::shared_ptr允许自定义所谓的“删除”动作,该动作是在计数为0时执行的。于是类Lock可以是下面的样子。
class Lock
{
public:
explicit Lock(Mutex* pm):mutexPtr(pm,unlock)
{lock(mutexPtr.get());} // 将mutexPtr指向的互斥变量加锁
private :
shared_ptr<Mutex> mutexPtr;
};
有没有发觉貌似少了点东西?对,析构函数没有了。因为share_ptr会帮你完成这一工作。
3.复制管理对象时也复制所管理的资源。
请回头想一个问题:为什么需要自己的资源管理类?那么,可能的理由是当不需要某个资源时,资源能被正常释放(删除,其他动作)。资源存在多个复件并不可怕,可怕的是复件在该销毁的时候却没有销毁。也就是,管理对象与所管理的资源要一一对应。为了保证这种对应关系,在复制管理对象时也复制所管理的资源。
4.转移资源的管理权。
在某些特殊场合下,你可能希望资源只被一个对象拥有,也就是管理对象在copying时要进行资源所有权的转移。从条款13中讲到的auto_ptr可以完美的实现这个需求。
■总结
1.复制管理对象时,请一并复制对象所管理的资源,资源的copy行为决定了管理对象的copy行为
2.普遍的RAII class的copy行为是抑制复制,使用引用计数
[Effective C++ --014]在资源管理类中小心copying行为的更多相关文章
- Effective C++(14) 在资源管理类中小心copying行为
问题聚焦: 上一条款所告诉我们的智能指针,只适合与在堆中的资源,而并非所有资源都是在堆中的. 这时候,我们可能需要建立自己的资源管理类,那么建立自己的资源管理类时,需要注意什么呢?. ...
- effective条款15,在资源管理类中小心copying行为
class A { private: int *p; void lock(){ cout << p << "is lock" << endl; ...
- 【14】在资源管理类中小心copying行为
1.为什么要使用资源管理类? 资源管理类的思路就是,栈上的对象,封装堆上分配的资源,确保一定会释放资源.auto_ptr和shared_ptr就是资源管理类,行为上像指针. 2.auto_ptr和sh ...
- EC笔记:第三部分:14、在资源管理类中小心Copying行为
场景 上一节实现了智能指针,其中的拷贝构造函数和赋值运算符是通过增加/减少指针的引用计数来操作的.但是如果是管理一个独占资源呢?我们希望在一个资源使用时被锁定,在使用完毕后被释放. #include ...
- 条款14:在资源管理类中小心copying行为
请牢记: 1.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 2.普遍常见的RAII class copying行为是:抑制copyin ...
- Effective C++ -----条款14: 在资源管理类中小心copying行为
复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 普遍而常见的RAII class copying行为是:抑制copying(使用私有继承 ...
- Effective C++ 条款13/14 以对象管理资源 || 在资源管理类中小心拷贝行为
三.资源管理 资源就是一旦你使用了它,将来不用的时候必须归还系统.C++中最常用的资源就是动态内存分配.其实,资源还有 文件描述符.互斥器.图形界面中的字形.画刷.数据库连接.socket ...
- Effective C++(15) 在资源管理类中提供对原始资源的访问
问题聚焦: 资源管理类是为了对抗资源泄露. 如果一些函数需要访问原始资源,资源管理类应该怎么做呢? 关于资源管理的概念总是显得那么的高大上,其实只是抽象一点. 下面用 ...
- [Effective C++ --015]在资源管理类中提供对原始资源的访问
引言 资源管理类是防止资源泄漏的有力武器,但是许多APIs直接指涉资源,除非你发誓永不使用这样的APIs,否则只得绕过资源管理对象(resource-managing objects)直接访问原始资源 ...
随机推荐
- 第一个MVC模式的程序
数据库 是一个SQL sever数据库,结构很简单,创建名为firstMVC的数据库,只包含一个数据表(名称为Persons),其中共有三列,分别用于保存人员(persons)的ID.姓名以及创建日期 ...
- 使用SQL Server 2005作业设置定时任务
公司有一个老项目由于直接把终端拍摄的图片以二进制的形式保存到数据库中,数据库比较大所以需要经常删除这些冗余数据,手动删除费时费力,项目组长让我把这些操作变成自动的,每天执行一次,只保留最近两个月的图片 ...
- SQL Server 外键约束的例子
外键约束的测试表与测试数据 -- 创建测试主表. ID 是主键. CREATE TABLE test_main ( id INT, value ), PRIMARY KEY(id) ); -- 创建测 ...
- 《深入Java虚拟机学习笔记》- 第17章 异常
<深入Java虚拟机学习笔记>- 第17章 异常
- e8_4输出菲波拉契数列的前10项
program fbnq;{输出菲波拉契数列的前10项} var a:..] of integer; i:integer; begin a[]:=; a[]:=; do a[i]:=a[i-]+a[i ...
- HDU 1561-The more, The Better(树状背包)
题意: n个城堡,每个有一定的财富,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡,求应攻克哪m个城堡,获得最大财富. 分析:dp[i][j],以i为根的子树,攻克j个城堡,获得的 ...
- BNU 51275 道路修建 Large 并查集
分析(引入Q神题解 %%%Q) 如果使用可持久化并查集,二分答案判定连通性,复杂度是O(mlog3n),不能在时限内出解.考虑到并查集实际上是一棵树,可以尝试在边上维护一些信息,假设t时刻加了一条边 ...
- [selenium webdriver Java]隐式的等待同步
Selenium WebDriver提供了隐式等待来同步测试.当使用了隐式等待执行测试的时候,如果WebDriver没有在DOM中找到元素,将继续等待,超出设定时间后,抛出找不到元素异常 即,当元素没 ...
- [JDBC-1] JDBC Base Template
以Statement建立的标准模板: static void template() throws Exception { Connection conn = null; Statement st = ...
- WSGI和PASTE
WSGI就是一个标准,WSGI server就是实现了这个标准的一个容器.这个标准类似于如下的东东: 1 2 3 4 5 6 7 8 9 10 11 from wsgiref.simple_serve ...