The following code doesn't compile under gcc-4.7.1 but compile under clang-3.2. Which one follows the C++11 standard?
struct X { virtual ~X() = default; }; struct Y : X { virtual ~Y() = default; };
gcc-4.7.1 complains that:
looser throw specifier for 'virtual Y::~Y()' error: overriding 'virtual X::~X() noexcept(true)'
Obviously, gcc-4.7.1 thinks X's default destructor nothrow, but Y's default destructor is not nothrow. Why is this? Can anyone refer to the correct place in standard? Thanks.
I saw similar questions on stackoverflow, but I didn't see the answers refering to the standard.
The default destructor calls the destructors of the base class and members of the derived class. The destructors of base classes and members are called in the reverse order of the completion of their constructor: The destructor for a class object is called before destructors for members and bases are called.
Any user-defined destructor is noexcept(true) by default, unless the declaration specifies otherwise, or the destructor of any base or member is noexcept(false) . Any deallocation function is noexcept(true) by default, unless the declaration specifies otherwise.
The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.
A trivial destructor is a destructor that performs no action. Objects with trivial destructors don't require a delete-expression and may be disposed of by simply deallocating their storage. All data types compatible with the C language (POD types) are trivially destructible.
The compilers are caught in a dilemma here, for the following reasons:
(1) Not specifying any exceptions in a function declaration (i.e. not using throw
nor noexcept
(which is equivalent to noexcept(true)
)) means to allow that function to throw all possible exceptions:
(§15.4/12, emphasis mine) A function with no exception-specification or with an exception-specification of the form
noexcept(constant-expression)
where theconstant-expression
yieldsfalse
allows all exceptions. [...]
(2) A default destructor must allow exactly the exceptions that are allowed by the functions directly invoked by its implicit definition:
(§15.4/14, emphasis mine) An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is 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 shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.
(3) When a special member (such as a destructor) is explicitly defaulted, i.e. when you use = default
, the exception specification is optional (see the use of "may have" below):
(8.4.2/2, emphasis mine) An explicitly-defaulted function [...] may have an explicit exception-specification only if it is compatible (15.4) with the exception-specification on the implicit declaration. [...]
There is no statement in the Standard that requires the exception specification in an explicitly defaulted destructor.
Conclusion: Therefore, not specifiying the exceptions of an explicitly defaulted destructor can be interpreted in two ways:
Unfortunately, GCC resolves this dilemma in one way (in favor of "no exceptions") in the case of your base class declaration, and in a different way in the case of the derived class (in favor of "all exceptions" there).
I believe the most natural interpretation of this admittedly ambiguous situation is to assume that (2) and (3) override (1). The Standard does not say so, but it should. Under that interpretation, Clang seems to be right here.
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