c++ - Is GotW #47 halfly wrong? -
the wrong solution
"aha," many people -- including many experts -- have said, "let's use uncaught_exception() figure out whether can throw or not!" , that's code in question 2 comes from... it's attempt solve illustrated problem:
// wrong solution // t::~t() { if( !std::uncaught_exception() ) { // ... code throw ... } else { // ... code won't throw ... } } the idea "we'll use path throw long it's safe throw." philosophy wrong on 2 counts: first, code doesn't that; second (and more importantly), philosophy in error.
the wrong solution: why code unsound
one problem above code won't work expected in situations. consider:
// why wrong solution wrong // u::~u() { try { t t; // work } catch( ... ) { // clean } } if u object destroyed due stack unwinding during exception propagation, t::~t fail use "code throw" path though safely could.
i believe explanation above incorrect, if std::uncaught_exception returns true always unsafe let function including destructor exit exception. prove
if function called during stack unwinding, after initialization of exception object , before start of exception handler, exits exception, std::terminate called. such functions include destructors of objects automatic storage duration scopes exited, , copy constructor of exception object called (if not elided) initialize catch-by-value arguments.
same words in c++ (terminate called in ~yyy()):
#include <exception> #include <iostream> int main(int argc, char* argv[]) { struct yyy { ~yyy() { std::cout << "during stack unwinding before throwing second exception " << std::uncaught_exception() << std::endl; throw std::exception(); } }; struct xxx { ~xxx() { std::cout << "after first exception thrown not catched " << std::uncaught_exception() << std::endl; if (std::uncaught_exception()) { try { yyy yyy; } catch (const std::exception&) { std::cout << "in second exception catch block " << std::uncaught_exception() << std::endl; } } } }; try { xxx xxx; std::cout << "before throwing first exception " << std::uncaught_exception() << std::endl; throw std::exception(); } catch (const std::exception&) { std::cout << "in first exception catch block " << std::uncaught_exception() << std::endl; } std::cout << "after both exceptions catched " << std::uncaught_exception() << std::endl; return 0; } my question did miss , herb sutter right specific case or absolutely wrong in piece of explanation?
it question of meant "any function called during stack unwinding" in standard text.
i believe intent prevent "any function called directly stack unwinding mechanism" terminate exception, i.e. throw (new) exception active stack unwinding session. requirement not supposed apply subsequent (nested) functions calls made internally function called original stack unwinding session.
as long new exceptions thrown , caught internally, without being allowed escape active stack unwinding session, allowed. herb's explanation in full agreement standard: possible throw new exceptions during stack unwinding long intercepted , suppressed internally.
your example calls terminate() different reason. compiling post-c++11 compiler. in c++11 destructors noexpect default, why yyy::~yyy() calls terminate() regardless of whether stack unwinding in progress, or of other external conditions (gcc warn that).
declare
~yyy() throw(std::exception) // or `noexcept(false)` { ... to test intended behavior of code. , no, not call terminate(): http://coliru.stacked-crooked.com/a/296ffb43b774409e
herb's outdated code, obviously, suffers same problem.
Comments
Post a Comment