Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: minor editorial changes

When an exception is thrown, the exception object operand of the throw expression is copied into a temporary object that is used to initialize the handler. The C++ Standard, [except.throw], paragraph 3 [ISO/IEC 14882-2014], states in part, states the following:

Throwing an exception copy-initializes a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler.

...

The copy constructor for an object thrown as an exception must be declared noexcept, including any implicitly-defined copy constructors. Note, any  Any function declared noexcept that terminates by throwing an exception violates ERR55-CPP. Honor exception specifications.

...

This compliant solution assumes that the type of the exception object can inherit from std::runtime_error, or that type can be used directly. Unlike std::string, a std::runtime_error object is required to correctly handle an arbitrary-length error message that is exception safe and guarantees the copy constructor will not throw [ISO/IEC 14882-2014]:.

Code Block
bgColor#ccccff
langcpp
#include <stdexcept>
#include <type_traits>

struct S : std::runtime_error {
  S(const char *msg) : std::runtime_error(msg) {}
};
 
static_assert(std::is_nothrow_copy_constructible<S>::value,
              "S must be nothrow copy constructible");

void g() {
  // If some condition doesn't hold...
  throw S("Condition did not hold");
}

void f() {
  try {
    g();
  } catch (S &s) {
    // Handle error
  }
}

...

If the exception type cannot be modified to inherit from std::runtime_error, a data member of that type is a legitimate implementation strategy, as shown in this compliant solution:.

Code Block
bgColor#ccccff
langcpp
#include <stdexcept>
#include <type_traits>

class S : public std::exception {
  std::runtime_error m;
public:
  S(const char *msg) : m(msg) {}
  
  const char *what() const noexcept override {
    return m.what();   
  }
};
 
static_assert(std::is_nothrow_copy_constructible<S>::value,
              "S must be nothrow copy constructible");
 
void g() {
  // If some condition doesn't hold...
  throw S("Condition did not hold");
}

void f() {
  try {
    g();
  } catch (S &s) {
    // Handle error
  }
}

...