Section 18.8.1 [exception]/p1 specifies:
namespace std {
class exception {
public:
exception() noexcept;
exception(const exception&) noexcept;
exception& operator=(const exception&) noexcept;
virtual ~exception();
virtual const char* what() const noexcept;
};
}
I.e. the copy constructor and copy assignment of std::exception shall be noexcept
, and this is testable with:
static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "");
static_assert(std::is_nothrow_copy_assignable<std::exception>::value, "");
I.e. if an implementation does not make these members noexcept, then it is not conforming in this regard.
Similarly, 18.6.2.1 [bad.alloc]/p1 also specifies noexcept copy:
namespace std {
class bad_alloc : public exception {
public:
bad_alloc() noexcept;
bad_alloc(const bad_alloc&) noexcept;
bad_alloc& operator=(const bad_alloc&) noexcept;
virtual const char* what() const noexcept;
};
}
Additionally, all of the std-defined exception types have noexcept copy members, either explicitly, or implicitly. For the types defined in <stdexcept>
this is usually implemented with a reference-counted buffer for the what()
string. This is made clear in [exception]/p2:
Each standard library class T
that derives from class exception
shall have a publicly accessible copy constructor and a publicly
accessible copy assignment operator that do not exit with an
exception. ...
That is, in a quality implementation (and it does not take heroics to create a quality implementation in this regard), not only will the copy members of exception types not throw an exception (naturally because they are marked noexcept
), they also will not call terminate()
.
There is no failure mode for copying the std-defined exception types. Either there is no data to copy, or the data is reference counted and immutable.