This question already has answers here:
Scope(failure) in C++11?
(2个答案)
7年前关闭。
毫无疑问,许多人熟悉Alexandrescus先生的ScopeGuard模板(现在是Loki的一部分)以及此处介绍的新版本ScopeGuard11:
http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C
来源在这里:
https://gist.github.com/KindDragon/4650442
在C++和2012年以后的演讲中,他提到他找不到正确检测由于异常而退出范围的方法。因此,他无法实现SCOPE_FAIL宏,该宏将仅当由于异常而退出作用域时,才执行提供的lambda(通常用于回滚代码)。这将导致不需要dismiss()成员函数,并使代码更具可读性。
由于我绝不像Alexandrescu先生那样天才或经验丰富,因此我希望实现SCOPE_FAIL并不像这样简单:
我的问题是为什么不呢?
您想在离开
(2个答案)
7年前关闭。
毫无疑问,许多人熟悉Alexandrescus先生的ScopeGuard模板(现在是Loki的一部分)以及此处介绍的新版本ScopeGuard11:
http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C
来源在这里:
https://gist.github.com/KindDragon/4650442
在C++和2012年以后的演讲中,他提到他找不到正确检测由于异常而退出范围的方法。因此,他无法实现SCOPE_FAIL宏,该宏将仅当由于异常而退出作用域时,才执行提供的lambda(通常用于回滚代码)。这将导致不需要dismiss()成员函数,并使代码更具可读性。
由于我绝不像Alexandrescu先生那样天才或经验丰富,因此我希望实现SCOPE_FAIL并不像这样简单:
~ScopeGuard11(){ //destructor
if(std::uncaught_exception()){ //if we are exiting because of an exception
f_(); //execute the functor
}
//otherwise do nothing
}
我的问题是为什么不呢?
最佳答案
对于具有析构函数的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
离开的伪造的ojit_code。10-04 15:06