C++中的RAII机制详解(4)
由于DoComplex函数的参数使用的传值,此时就会发生值的复制,会调用类的复制构造函数,生成一个临时的对象,由于MyLock没有实现复制构造函数,所以就是使用的默认复制构造函数,然后在DoComplex中使用这个临时变量。当调用完成以后,这个临时变量的析构函数就会被调用,由于在析构函数中调用了LeaveCriticalSection,导致了提前离开了CRITICAL_SECTION,从而造成对gGlobal变量访问冲突问题,如果在MyLock类中添加以下代码,程序就又能正确运行:
MyLock( const MyLock & temp )
{
EnterCriticalSection(&cs);
}
这是因为CRITICAL_SECTION 允许多次EnterCriticalSection,但是,LeaveCriticalSection必须和EnterCriticalSection匹配才能不出现死锁的现象。
为了避免掉进了这个陷阱,同时考虑到封装的是资源,由于资源很多时候是不具备拷贝语义的,所以,在实际实现过程中,MyLock类应该如下:
class MyLock
{
public:
MyLock()
{
EnterCriticalSection(&cs);
}
~MyLock()
{
LeaveCriticalSection(&cs);
}
private:
MyLock(const MyLock &);
MyLock operator =(const MyLock &);
};
这样就防止了背后的资源复制过程,让资源的一切操作都在自己的控制当中。如果要知道复制构造函数和赋值操作符的调用,可以好好的阅读一下《深度探索C++对象模型这本书》。
总结
说了这么多了,RAII的本质内容是用对象代表资源,把管理资源的任务转化为管理对象的任务,将资源的获取和释放与对象的构造和析构对应起来,从而确保在对象的生存期内资源始终有效,对象销毁时资源一定会被释放。说白了,就是拥有了对象,就拥有了资源,对象在,资源则在。所以,RAII机制是进行资源管理的有力武器,C++程序员依靠RAII写出的代码不仅简洁优雅,而且做到了异常安全。在以后的编程实际中,可以使用RAII机制,让自己的代码更漂亮。
- 上一篇:C++设计模式之建造者模式
- 下一篇:C++设计模式之单例模式