Resource Acquisition Is Initialization
C++ 的 RAII(Resource Acquisition Is Initialization)机制使用面向对象的特性可以容易地处理这个事情。RAII 其实使用 C++ 类的机制,在构造函数中分配资源,在析构函数中释放资源。下面看个例子。
std::mutex m; void bad() { m.lock(); // 请求互斥 f(); // 若f()抛异常,则互斥绝不被释放 if(!everything_ok()) return; // 提早返回,互斥绝不被释放 m.unlock(); // 若bad()抵达此语句,互斥才被释放 }
上面这个例子,在函数的第三条语句提前返回了,直接导致 m.unlock() 没有被调用,这样会引起死锁问题。我们来看一下用 RAII 的方式是怎样解决这个问题的。
//首先,先声明一个RAII类,注意其中的构造函数和析构函数 class LockGuard { public: LockGuard(std::mutex &m):_m(m) { m.lock(); } ~LockGuard() { m. unlock(); } private: std::mutex& _m; } //然后,我们来看一下,怎样使用的 void good() { LockGuard lg(m); // RAII类:构造时,互斥量请求加锁 f(); // 若f()抛异常,则释放互斥 if(!everything_ok()) return; // 提早返回,LockGuard析构时,互斥量被释放 } // 若good()正常返回,则释放互斥
try { ... // 正常的业务代码 } catch (Exception1 e) { ... // 处理异常 Exception1 的代码 } catch (Exception2 e) { ... // 处理异常 Exception2 的代码 } finally { ... // 资源清理的代码 }