Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added compliant solution.

...

Exceptions thrown in destructors of objects with static storage duration or in constructors of namespace-scope objects with static storage duration are not caught by a function-try-block on main(). Exceptions thrown in destructors of objects with thread storage duration or in constructors of namespace-scope objects with thread storage duration are not caught by a function-try-block on the initial function of the thread.

To illustrate using an example:

Non-Compliant Code Example

In the following non-compliant example, the constructor of global may throw an exception during program startup. This exception is not caught by the function-try-block on main(), resulting in a call to std::terminate(). Similarly, the destructor of the local_static object defined in function f(() may throw an exception during program termination. This exception is also not caught by the function-try-block on main(), again resulting in a call to std::terminate().

Code Block
bgColor#FFcccc

static const std::string global("...");

void f() {
  static const struct LocalClass {
Code Block

struct Foo {
  Foo();    // may throw
};

Foo A;

void bar...
    ~LocalClass() { if (error_detected) throw std::runtime_error("..."); }
  static Foo B} local_static;
}

int main()
try {
  barf();
  // other executable statements
}
catch(...) {
  // will catchhandle exceptions thrown during fromthe bar()call andto
  // f() and any other executable statements in the try block
  // block above

  // IMPORTANT: will not catch exceptions thrown
  // from the constructor of theglobal globalor objectthose Afrom
  // or those from the destructor of the static local_static defined in f()
  // localand objectinvoked Bduring defined in bar()program termination
}

Compliant Solution

Compliant code must prevent exceptions from escaping during program startup and termination. A solution is to avoid defining at namespace scope objects whose constructors may throw, in addition to preventing exceptions from being thrown from destructors as outlined in Thus, it is important to prevent constructors of objects with static storage duration to throw exceptions. See also ERR33-CPP. Destructors must not throw exceptions.

Code Block
bgColor#ccccff

static const char global[] = "...";

void f() {
  static const struct LocalClass {
    // ...
    ~LocalClass() throw() {
      if (error_detected) {
        try {
          std::clog << "Runtime error: ...\n";
        }
        catch(...) {
          // attempt to log error by other means
        }
    }
  } local_static;
}

int main()
try {
  f();
}
catch(...) {
  // handle exceptions thrown during the call to
  // f() and any other statements in the try block
  // above
}

References

Wiki Markup
\[[Sutter 00|AA. C++ References#Sutter 00]\] Sutter, Herb. Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions.