Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++-4.8.1 thinks that an explicitly-declared destructor with no exception specification is always noexcept(true)

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).

like image 584
Travis Gockel Avatar asked Jun 18 '13 19:06

Travis Gockel


People also ask

Are destructors noexcept in C++?

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:

What if no prospective destructor is provided for a class type?

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.

How does a destructor terminate in C++?

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.

Which constructor is provided automatically if no constructors are explicitly declared?

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?


1 Answers

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-specification noexcept(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, [...].

like image 117
Xeo Avatar answered Sep 16 '22 21:09

Xeo