All of GCC 4.8.4, 4.9.3, 5.3.0 pass the tests for std::exception
(for any of -std=c++11/1y/14/1z/17 options, where available):
static_assert(std::is_nothrow_copy_constructible<std::exception>::value, "test exception");
static_assert(std::is_nothrow_copy_assignable <std::exception>::value, "test exception");
Which is fine, since std::exception
has noexcept special members (C++14 18.8.1):
namespace std { class exception { public: exception() noexcept; exception(const exception&) noexcept; exception& operator=(const exception&) noexcept; virtual ~exception(); virtual const char* what() const noexcept; }; }
Unfortunately, all of the compilers above fail on the following static_assert
s:
static_assert(std::is_nothrow_copy_constructible<std::runtime_error>::value, "test runtime_error");
static_assert(std::is_nothrow_copy_assignable <std::runtime_error>::value, "test runtime_error");
The standard contains only the following about std::runtime_error
in 19.2.6:
namespace std { class runtime_error : public exception { public: explicit runtime_error(const string& what_arg); explicit runtime_error(const char* what_arg); }; }
But nothing is said about the noexcept
ness of the other (implicitly declared special) members nor the storage implementation requirements of what_arg
.
The standard (C++14) says the following in 15.4/14:
An inheriting constructor (12.9) and an implicitly declared special member function (Clause 12) have an exception-specification. If f is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions.
And the following in 18.8.1/2:
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.
Since std::runtime_error
does not expose the implementation of the what_arg
storage, we do not know whether it's (special) members are noexcept or not, so the noexceptness of std::runtime_error
's copy constructor or copy assignment members are undecidable. Our only bet is 18.8.1 above.
Question 1/a) We consider std::runtime_error
's copy constructor or copy assignment to be noexcept (1, 2). Is this true / state-of-the-art / best practice?
Question 1/b) Do not we need to explicitly state this in the standard? (Like in 18.8.2, Class bad_exception
)
Question 1/c) Is it a bug in GCC that it fails the static_assert tests above?
Question 2) If the above deduction is wrong, could someone point me to the section(s) in the standard which state that std::runtime_error has noexcept copy constructor (and copy assignment)? (Or where it states that they are not.)
std::runtime_error
? It seems that gcc 5.2.0 passes the tests. - cpplearnernoexcept
for llvm's libc++, and for VS-2015. melpon.org/wandbox/permlink/DzUHKeD4c4MXOvQH reports them noexcept for gcc's 5.1 and above. - Howard Hinnant