Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behavior of std::is_nothrow_destructible

The following code triggers static_assert even though I don't think it should:

#include <type_traits>

template< typename T >
struct Tmp
{
  ~Tmp() noexcept( std::is_nothrow_destructible< T >::value ) {}
};

struct Foo;

struct Bar
{
  // Comment this out for the problem to go away
  Tmp< Foo > xx;

  // ..or this
  Bar() {}
};

struct Foo {};

// This triggers
static_assert( std::is_nothrow_destructible< Foo >::value, "That's odd" );

int main()
{
}

When compiled with:

g++-4.9 -std=c++11 nothrow_destructible_bug.cc

The following happens:

nothrow_destructible_bug.cc:20:1: error: static assertion failed: That's odd
 static_assert( std::is_nothrow_destructible< Foo >::value, "That's odd" );
 ^

How come just using Foo to instantiate a template in an unrelated class make it lose its noexcept status? I thought this was a compiler bug, but I tried it with all recent versions of both gcc and clang and they all seem to give the same error.

like image 583
dragonroot Avatar asked Sep 27 '22 13:09

dragonroot


1 Answers

Where you use Tmp< Foo > xx, Foo is an incomplete type. This violates one of the preconditions for use of is_nothrow_destructible, and its use is undefined behavior. One possibility of that UB is for is_nothrow_destructible to be false.

Commenting out the use of Tmp will avoid that issue. Since the template is not instantiated until it is used, commenting out the constructor will also avoid the problem because the template won't yet be instantiated.

Moving the definition of the struct Foo before Bar should also avoid the problem.

like image 160
1201ProgramAlarm Avatar answered Oct 05 '22 07:10

1201ProgramAlarm