条款14:在资源管理类中小心copy行为
修改了一下书中代码(参考http://www.cnblogs.com/jerry19880126/archive/2013/05/25/3098997.html)
#include<iostream> #include<cstring> #include<cstdio> #include<memory> using namespace std; class Lock { public: Lock(int *pm) : mutexPtr(pm){ lock(mutexPtr); } ~Lock(){ unlock(mutexPtr); } private: int *mutexPtr; void lock(int* a){ cout<<"adress is "<<a<<"is locked\n"; } void unlock(int* a){ cout<<"adress is "<<a<<"is unlock\n"; } }; int main(){ Lock a(new int(10)); Lock b(a); return 0; }
运行程序可以发现输出为
adress is 0x590cc8is locked
adress is 0x590cc8is unlock
adress is 0x590cc8is unlock
也就是说,locked执行了一次,但是unlock却执行了两次。两个对象中的指针指向同一个资源,如果unlock中对内存进行读取修改的话,是非常有可能出错的、
解决上述问题有两种方法,一种是条款6,直接禁止赋值函数以及拷贝构造函数
class Lock { public: Lock(int *pm) : mutexPtr(pm){ lock(mutexPtr); } ~Lock(){ unlock(mutexPtr); } private: int *mutexPtr; void lock(int* a){ cout<<"adress is "<<a<<"is locked\n"; } void unlock(int* a){ cout<<"adress is "<<a<<"is unlock\n"; } Lock& operator=(const Lock&); Lock(const Lock&); };
这样便无法使用赋值函数和拷贝构造函数(一旦使用会提示你编译不通过)
第二种是对底层资源使用”引用计数法“。有时候我们又希望保有资源,直到它的最后一个使用者被销毁。这种情况下复制RAII对象时,应该将资源的”被引用计数“递增。tr1::shared_ptr便是如此。
class Lock { public: Lock(int *pm) :mutexPtr(pm){ lock(mutexPtr); } ~Lock(){ unlock(mutexPtr); } private: shared_ptr<int> mutexPtr; void lock(shared_ptr<int> mutexPtr){ cout<<"adress is "<<"is locked\n"; } void unlock(shared_ptr<int> mutexPtr){ cout<<"adress is "<<"is unlock\n"; } };