指针和虚函数表

C++ 的 ScopeExitGuard

輝夜(tadvent) posted @ 2014年12月12日 15:18 in C/C++ with tags c++ , 1134 阅读

C++ 提供了 RAII 机制,并提倡使用它来管理各种资源,可是在实际中会发现这一套使用起来并不如想象中的那么方便。在 Linux 下开发会遇到大量 open() / close() 或是 malloc() / free() 类似操作,而且大部分都没有现成好用的 C++ wrapper,如果每组操作都自己去寨一个 class OperationGuard 只用来管理资源释放未免又显得过于繁琐。

其实我需要的只是在退出作用域时自动执行一些清理操作,如果能方便的把要进行的操作封装在一个临时对象的析构函数里就好了。在网上搜索了一下,果然已经有 很多人想到了这个问题,现成的实现有 Boost 的 SCOPE_EXIT,看了一下支持的功能很多,用起来也比想象中复杂了不少。于是还是自己来寨一个好了,也不用很复杂:(以下实现参考了SCOPE(EXIT) IN C++11

template<class F>
class ScopeExitGuard_Impl{
    F _f;
public:
    ScopeExitGuard_Impl(F f) : _f(f) {}
    ~ScopeExitGuard_Impl(){
        _f();
    }
};
template<class F>
ScopeExitGuard_Impl<F> ScopeExitGuard(F f){
    return ScopeExitGuard_Impl<F>(f);
}

#define SCOPE_EXIT_GUARD(code) \
    auto scope_exit_##__LINE__ = ScopeExitGuard([&]{code;})

C++11 的 lambda 真是好用啊。在 SCOPE(EXIT) IN C++11 那篇中,lambda 使用了 [=] 来获取外部变量,这样一来就只能读取,无法改写。我在上面的 lambda 中改为 [&] 方便改写外部变量。

使用起来很简单:

int a = 1;
{
    SCOPE_EXIT_GUARD(a = 2);
    a = 3;
}
cout << a << endl; // print: 2
{
    int *p = (int*)::operator new(100 * sizeof(int));
    // label 1
    SCOPE_EXIT_GUARD(::operator delete(p));
    for (int i = 0; i < 10; ++i){
        p[i] = i;
    }
}

如果在 ::operator new() 语句或 label 1 处抛出异常,::operator delete() 就不会被调用,因此只需把释放资源的 SCOPE_EXIT_GURAD 语句与申请资源的语句放在一起就好。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter