为什么不能Alexandrescu的使用std :: uncaught_exception()在S

2019-08-17 01:07发布

这个问题已经在这里有一个答案:

  • 范围(失败)在C ++ 11? 2个回答

很多人都毫无疑问熟悉Alexandrescus ScopeGuard先生模板(现在是洛基的一部分)和新版本ScopeGuard11这里介绍: http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-安德烈- Alexandrescu的系统性,错误处理-在-C

与源这里: https://gist.github.com/KindDragon/4650442

他在C ++和2012年以后的谈话,他提到,他能不能找到一种方法,如果范围正在因为异常退出正确检测。 因此他无法实现SCOPE_FAIL宏当且仅当范围退出,因为一个例外,其将执行所提供的拉姆达(通常用于回滚代码)。 这将使得解雇()成员函数不再需要,使代码更易读。

由于我绝不为天才或体验为Alexandrescu的先生我希望实现SCOPE_FAIL是不是因为这很容易:

~ScopeGuard11(){                      //destructor
    if(std::uncaught_exception()){    //if we are exiting because of an exception
        f_();                         //execute the functor
    }
    //otherwise do nothing
}

我的问题是,为什么不呢?

Answer 1:

随着ScopeGuard11有你的析构函数的类,成员f_可以被调用,即使它不是当前范围(即应该通过保护来保护)正被由于退出到异常。 这个后卫的使用中可能例外清理过程中使用的代码是不安全的。

试试下面这个例子:

#include <exception>
#include <iostream>
#include <string>

// simplified ScopeGuard11
template <class Fun>
struct ScopeGuard11 {
     Fun f_;
     ScopeGuard11(Fun f) : f_(f) {}
     ~ScopeGuard11(){                      //destructor
        if(std::uncaught_exception()){    //if we are exiting because of an exception
            f_();                         //execute the functor
         }
         //otherwise do nothing
      }
};

void rollback() {
  std::cout << "Rolling back everything\n";
}
void could_throw(bool doit) {
  if (doit) throw std::string("Too bad");
}

void foo() {
   ScopeGuard11<void (*)()> rollback_on_exception(rollback);
   could_throw(false);
   // should never see a rollback here
   // as could throw won't throw with this argument
   // in reality there might sometimes be exceptions
   // but here we care about the case where there is none 
}

struct Bar {
   ~Bar() {
      // to cleanup is to foo
      // and never throw from d'tor
      try { foo(); } catch (...) {}
   }
};

void baz() {
   Bar bar;
   ScopeGuard11<void (*)()> more_rollback_on_exception(rollback);
   could_throw(true);
}

int main() try {
   baz();
} catch (std::string & e) {
   std::cout << "caught: " << e << std::endl;
}

你会希望看到一个rollback离开时baz ,但你会看到两个-包括离开虚假一个foo



文章来源: Why can't Alexandrescu use std::uncaught_exception() to implement SCOPE_FAIL in ScopeGuard11? [duplicate]