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

Non-trivial destructor make class non-trivially-constructible

本文关键字:析构函数      更新时间:2023-10-16

考虑以下代码:

#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进行了良好的编译:实例。但总结标准:

如果以下全部为真,则类T的默认构造函数是琐碎的(即不执行任何操作):

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

正如我所看到的,并没有依赖于析构函数的琐碎性。

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

附加

我找到了一个变通方法:是static_assert(__has_trivial_constructor( N ));内置的类型特性。在clanggccMSVC中都有支持。

对于类型性状的is_noexcept_constructible家族,也有变通方法。

此问题包含在LWG问题2116:std::swap noexcept(什么?)中,我们可以从std::is_trivialy_default_constructible:的cppreference部分看到这一点

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

它似乎只谈论CCD_ 8,但如果我们详细阅读这个问题,我们会发现它也适用于这里。

如果我们遵循gcc错误报告,也许会更容易:[DR2116]has_nothrow_.*首先引用的构造函数错误说:

检测另一行可构建性的特征是有缺陷的,因为它们受到对象是否具有另一行dtor的影响;destruction是在noexcept(…)运算符中的完整表达式求值结束时调用的。他们都使用构建临时内部noexcept的模式,而他们应该使用放置新的

这明确地说明了LWG问题中真正提到的内容,最终说:

is_nothrow_constructible是在is_constructable的术语中定义的,is_construct是通过查看一个假设变量并询问变量定义是否已知不会抛出异常来定义的。该问题声称,在给定上下文的情况下,这也会检查类型的析构函数,因此,如果析构函数可能引发,则会返回false。如果构造函数为noexcept(true),而析构函数为noexception(false),则至少有一个实现(Howard的)返回false。因此,这不是一个紧张的解释。问题是要求将其定义为新的放置,而不是临时对象,以使is_nothrow_constructible只查看构造函数的noexcept状态,而不查看析构函数。

这也影响了依赖于std::is_trivialy_constructible的CCD_ 9,其作用与CCD_

但是变量定义不调用任何非平凡的操作