Consider the following program:
#include <type_traits>
struct Thrower
{
~Thrower() noexcept(false) { throw 1; }
};
struct Implicit
{
Thrower t;
};
static_assert(!std::is_nothrow_destructible<Implicit>::value, "Implicit");
struct Explicit
{
~Explicit() {}
Thrower t;
};
static_assert(!std::is_nothrow_destructible<Explicit>::value, "Explicit");
With g++-4.8.1
, there is a static assertion failure on Explicit
-- it seems to think that ~Explicit()
is noexcept
. This does not match my expectations. According to §12.4.3:
A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration
The funny thing here is the check of Implicit
seems to be behaving according to my interpretation of §15.4.14 (through §12.4.7).
...If f is an...destructor...it's implicit exception-specification specifies...f has the exception-specification
noexcept(true)
if every function it directly invokes allows no exceptions.
g++-4.7
lacks is_nothrow_destructable
, I wrote my own to check the behavior in 4.7. The program seems to compile perfectly fine. I reserve the right for this to be completely wrong and the source of my confusion:
template <typename T>
struct is_nothrow_destructible
{
static constexpr bool value = noexcept(std::declval<T>().~T());
};
TL;DR: Why does g++-4.8.1
think that an explicitly-declared destructor with no exception specification is always noexcept(true)
?
Update: I opened a bug on this: 57645. If you really need to work around this issue, you can add an exception specification to the destructor (like Thrower
has in the example).
In practice, implicit destructors are noexcept unless the class is "poisoned" by a base or member whose destructor is noexcept (false) . The implicitly-declared or defaulted destructor for class T is undefined (until C++11)defined as deleted (since C++11) if any of the following is true:
If no user-declared prospective (since C++20) destructor is provided for a class type ( struct, class, or union ), the compiler will always declare a destructor as an inline public member of its class.
As any other function, a destructor may terminate by throwing an exception (this usually requires it to be explicitly declared noexcept(false)) (since C++11), however if this destructor happens to be called during stack unwinding, std::terminate is called instead.
A default constructor is provided automatically if no constructors are explicitly declared in the class. D. The default constructor is a no-arg constructor. Which of the following statements are true?
TL;DR: Why does g++-4.8.1 think that an explicitly-declared destructor with no exception specification is always
noexcept(true)
?
Because it has a bug?
Your interpretation of the standard is correct, and Clang implements it correctly (the assert doesn't fire).
f
has the exception-specificationnoexcept(true)
if every function it directly invokes allows no exceptions.
A destructor directly invokes the destructor of all subobjects:
§12.4 [class.dtor] p8
:
After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class
X
calls the destructors for X’s direct non-variant non-static data members, [...].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With