非平凡的析构函数使类非平凡可构造

时间:2015-11-25 05:55:32

标签: c++ destructor

请考虑以下代码:

#include <type_traits>

struct T {};

static_assert(std::is_trivially_destructible< T >{});
static_assert(std::is_trivially_default_constructible< T >{});

struct N { ~N() { ; } };

static_assert(!std::is_trivially_destructible< N >{});
static_assert(!std::is_trivially_default_constructible< N >{});

使用clang 3.7.0编译好live example。但总结the Standard

  

如果满足以下所有条件,则类T的默认构造函数是微不足道的(即不执行任何操作):

     
      
  • 构造函数不是用户提供的(即,是隐式定义或默认的)
  •   
  • T没有虚拟成员函数
  •   
  • T没有虚拟基类
  •   
  • T没有使用默认初始值设定项的非静态成员。   (自C ++ 11起)
  •   
  • T的每个直接基础都有一个普通的默认构造函数
  •   
  • 类类型的每个非静态成员都有一个普通的默认构造函数
  •   

正如我所看到的,不依赖于析构函数的微不足道。

我错过了什么?是clang bug吗?

其他

我找到了一个解决方法:static_assert(__has_trivial_constructor( N ));是内置类型特征。 clanggccMSVC支持。

对于is_noexcept_constructible类型特征系列there is workaround也是如此。

1 个答案:

答案 0 :(得分:6)

LWG issue 2116: std::swap noexcept(what?)中介绍了此问题,我们可以在std::is_trivially_default_constructible的cppreference部分看到这一点:

  

在许多实现中,is_nothrow_default_constructible还检查析构函数是否抛出,因为它实际上是noexept(T()):GCC bug 51452 LWG issue 2116

其中仅仅涉及is_nothrow_default_constructible,但如果我们详细阅读该问题,我们也会看到它也适用于此。

如果我们首先引用gcc bug report: [DR 2116] has_nothrow_.*constructor bugs首先引用的话,那么也许会更容易:

  

检测nothrow可构造性的特征是错误的,因为它们受到对象是否具有不可靠性的影响;在noexcept(...)运算符的完整表达式的求值结束时调用destroy。他们都使用构建临时内部noexcept的模式,而他们应该使用placement new

这明确说明LWG问题中唯一真正提到的内容最终会说:

  

is_nothrow_constructible在is_constructible的术语中定义,通过查看假设变量并询问变量定义是否已知不会抛出异常来定义。该问题声称,在给定上下文的情况下,这也会检查类型的析构函数,因此如果析构函数可能抛出,则返回false。如果构造函数为noexcept(true)且析构函数为noexcept(false),则至少有一个实现(Howard's)会返回false。所以这不是一个紧张的解释。问题是要求使用placement new来定义它,而不是根据临时对象来定义,以便更清楚地表明is_nothrow_constructible只查看构造函数的noexcept状态,而不是析构函数。

也影响std::is_trivially_default_constructibleis_constructible依赖std::is_trivially_constructible$employees = array( 123 => array( 'id' => 13, 'firstname' => 'Marky', 'lastname' => 'Mark' ), 213 => array( 'id' => 3, 'firstname' => 'Bobby', 'lastname' => 'Bob' ), 256 => array( 'id' => 42, 'firstname' => 'Jimmy', 'lastname' => 'Jim' ) ); 相同但又有以下限制:

  

但变量定义不会调用任何不重要的操作