【问题起源】
假设有这么个函数:
看起来似乎没什么问题。但是面向对象里有异常这么回事,如果一个异常抛出又没被处理,就会直接退出该级函数到上一层去。如果dosomething()中有异常抛出,这里delete p就不会被执行,造成资源泄露。为了解决这个问题,就得手工在异常处理里delete一遍:
然而这么写实在是麻烦。
【解决方案】RAII
RAII是Resource Acquisition Is Initialization的缩写,中文是资源获得式初始化。它利用了栈上的变量会被自动销毁的事实。
这时如果dosomething有异常抛出,p作为栈上的局部变量会被自动销毁,~PtrClass()会被自动调用,于是可以保证 new出来的int *会被销毁。
【应用二】
就算不考虑异常安全,这种技术也可以带来便利:
这里foo_1(), foo_2(), foo_3()是别处定义好的函数,如果返回真则foo()没有必要再往下走。那么多delete a就是为了保证不资源泄露。(我们先不讨论这个函数是否会有更好的设计方案。)如果采用上面的RAII就不用这么麻烦了。这里只有一个指针,可能看起来简单;不妨想象一下有100个new出来的指针需要删除的情况,foo_n()有100个的情况。。。。
【应用三】多线程锁
多线程编程里,有时候会出现加锁之后忘了解锁的情况:
这里的麻烦仍然在于异常。如果DoSomething()抛出异常,这里有没有处理,那么mutex就永远处于被锁住的状态了。这时候如果应用RAII,就没有这样的问题了:
因为异常退出时所有栈上的局部变量会被自动销毁,所以mutex会被解锁。
提个问题:这里 myMutex m(mutex); 有没有可能让编译器给优化掉?