RAII
RAII,
RAII
作用
[编辑]RAII
#include <string>
#include <mutex>
#include <iostream>
#include <fstream>
#include <stdexcept>
void write_to_file(const std::string & message)
{
// 创建关于文 件 的 互斥锁
static std::mutex mutex;
// 在 访问文 件 前 进行加 锁
std::lock_guard<std::mutex> lock(mutex);
// 尝试打 开文件
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("unable to open file");
// 输出文 件 内容
file << message << std::endl;
// 当 离开作用 域 时,文 件 句柄 会 被 首 先 析构 (不 管 是 否 抛 出 了 异常)
// 互斥锁也会 被 析构 (同 样地,不 管 是 否 抛 出 了 异常)
}
C++
典型 用法
[编辑]RAII
template <class Mutex> class lock_guard {
private:
Mutex& mutex_;
public:
lock_guard(Mutex& mutex) : mutex_(mutex) { mutex_.lock(); }
~lock_guard() { mutex_.unlock(); }
lock_guard(lock_guard const&) = delete;
lock_guard& operator=(lock_guard const&) = delete;
};
extern void unsafe_code(); // 可能 抛 出 异常
using std::mutex;
using std::lock_guard;
mutex g_mutex;
void access_critical_section()
{
lock_guard<mutex> lock(g_mutex);
unsafe_code();
}
实际
RRID
[编辑]RAII还有另外一种被称为RRID(Resource Release Is Destruction)
#include <functional>
class ScopeGuard {
private:
typedef std::function<void()> destructor_type;
destructor_type destructor_;
bool dismissed_;
public:
ScopeGuard(destructor_type destructor) : destructor_(destructor), dismissed_(false) {}
~ScopeGuard()
{
if (!dismissed_) {
destructor_();
}
}
void dismiss() { dismissed_ = true; }
ScopeGuard(ScopeGuard const&) = delete;
ScopeGuard& operator=(ScopeGuard const&) = delete;
};
ScopeGuard
void foo()
{
auto fp = fopen("/path/to/file", "w");
ScopeGuard fp_guard([&fp]() { fclose(fp); });
write_to_file(fp); // 异常安全
}
void access_critical_section()
{
Mutex m = new Mutex;
lock(m);
scope(exit) unlock(m);
unsafe_code(); // 异常安全
}
Resource create()
{
Resource r = new Resource();
scope(failure) close(f);
preprocess(r); // 抛 出 异常时会自 动调用 close(r)
return r;
}
與 finally的 比較
[编辑]虽然RAII
void foo() {
Socket socket;
try {
socket = new Socket();
access(socket);
} finally {
socket.close();
}
}
void foo() {
try (Socket socket = new Socket()) {
access(socket);
}
}
参考 资料
[编辑]- Stroustrup, Bjarne. The C++ Programming Language [C++
程 序 设计语言]. Addison-Wesley. 2000 [2014-09-29]. ISBN 0-201-70073-5. (原始 内容 存 档于2014-06-30) (英 语). - Stroustrup, Bjarne. The Design and Evolution of C++ [C++语言
的 设计和 演 化 ]. Addison-Wesley. 1994 [2014-09-29]. ISBN 0-201-54330-3. (原始 内容 存 档于2023-06-06) (英 语). - Wilson, Matthew. ,Imperfect C++ [Imperfect C++
中 文 版 ]. Addison-Wesley. 2004 [2023-11-10]. ISBN 0321228774. (原始 内容 存 档于2023-06-05) (英 语).
- ^ Exception Handling for C++ (页面
存 档备份,存 于互联网档案 馆), 5 Handling of Destructors - ^ Stroustrup 1994,chpt. 16.5 Resource Management. I called this technique “resource acquisition is initialization.”
- ^ C++ FAQ, "I have too many try blocks; what can I do about it?" (页面
存 档备份,存 于互联网档案 馆) - ^ 4.0 4.1 Stroustrup 2000,chpt. 14.4.1 Using Constructors and Destructors.
- ^ C++ FAQ, "What's the order that local objects are destructed?" (页面
存 档备份,存 于互联网档案 馆) - ^ lock_guard(页面
存 档备份,存 于互联网档案 馆) - ^ Wilson 2004,chpt. 3.4 RRID.
- ^ Andrei Alexandrescu, Change the Way You Write Exception-Safe Code (页面
存 档备份,存 于互联网档案 馆) - ^ Boost.ScopeExit(页面
存 档备份,存 于互联网档案 馆) - ^ Bjarne Stroustrup's C++ Style and Technique FAQ (页面
存 档备份,存 于互联网档案 馆). "Why doesn't C++ provide a "finally" construct?" (页面存 档备份,存 于互联网档案 馆)