Ответ 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;
}
Если вы оставите baz
, вы захотите увидеть один rollback
, но вы увидите два - включая ложный, выходящий из foo
.