Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default destructor nothrow

Tags:

c++

c++11

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.

like image 343
Kan Li Avatar asked Jul 16 '12 01:07

Kan Li


People also ask

Is there a default destructor in c++?

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.

Are destructors Noexcept by default?

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.

What is noexcept used for in c++?

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.

What is trivial destructor in c++?

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.


1 Answers

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 the constant-expression yields false 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:

  • To mean that all exceptions are allowed (according to (1) above)
  • Or, alternatively, to mean that exactly the same exceptions are allowed as are allowed by the implicit default definition of the destructor (according to (3) above), which in your case means to allow no exceptions (according to (2) above).

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.

like image 76
jogojapan Avatar answered Oct 03 '22 00:10

jogojapan