
Hi Howard, Howard Hinnant wrote:
class sticky_exception { bool owns_; sticky_exception& operator=(const sticky_exception&); public: sticky_exception() : owns_(true) {} sticky_exception(sticky_exception& s) : owns_(s.owns_) {s.owns_ = false;} // sticky_exception(sticky_exception&& s) : owns_(s.owns_) {s.owns_ = false;} ~sticky_exception() {if (owns_) {sticky_exception s; throw s;}} };
Does this destructor not invoke some kind of recursive nuttiness that leads to std::terminate()? If a sticky_exception is created on "the stack", any throw statements made thereafter in the same scope will invoke the destructor of that sticky_exception, at which point we end up doing this (calling ~sticky_exception) all over again. I though 15.5.1 would apply, here? "In the following situations exception handling must be abandoned for less subtle error handling techniques: [...] -- when the destruction of an object during stack unwinding (15.2) exits using an exception [...] In such cases, void terminate(); is called (18.6.3)." For example, the following program prints "genesis!" and "terminating!", but not "death!" (at least with MSVC8, gcc 3.4.5, gcc 4.2.1 and DMC 8.42n. Borland bcc32 5.82 disagrees): #include <exception> #include <iostream> class sticky_exception { bool owns_; sticky_exception& operator=(const sticky_exception&); public: sticky_exception() : owns_(true) {} sticky_exception(sticky_exception& s) : owns_(s.owns_) {s.owns_ = false;} ~sticky_exception() {if (owns_) {sticky_exception s; throw s;}} }; struct noisy { noisy() { std::cerr << "genesis!\n"; } ~noisy() { std::cerr << "death!\n"; } }; void handler() { std::cerr << "terminating!\n"; } int main() { std::set_terminate(handler); { noisy n; sticky_exception s; throw s; } return 0; } So how is creating a sticky_exception any different to a glorified call to std::terminate() (at the end of scope)? Or am I missing something crazy-obvious? Cheers, Edd