以下代码无法使用Visual Studio 2017(15.5),gcc 6.4.0和clang 4.0.1进行编译,即静态断言失败:
struct Type
{
Type(Type&&) noexcept {}
~Type() noexcept(false) {}
};
static_assert(std::is_nothrow_move_constructible<Type>::value, "Type should be nothrow-move-constructible");
static_assert(std::is_nothrow_constructible<Type, Type&&>::value, "Type should be nothrow-constructible from Type&&");
C ++标准是否正确? std::is_nothrow_move_constructible
是否需要 noexcept 析构函数?为什么呢?
如果我使用如下:
Type a;
Type b(std::move(a));
在第二个语句中没有调用a
的析构函数。
答案 0 :(得分:1)
我们可以看到std::is_nothrow_move_constructible
是根据is_nothrow_constructible_v定义的。因此,此问题最终被LWG issue 2116: is_nothrow_constructible and destructors
所覆盖,该问题尚未解决,因此除非问题的解决方法与当前实现方式不同,否则它不是错误。
它将打开,并进行以下讨论:
IMO(如果我们指定is_ [nothrow_]可以根据变量构造) 声明的有效性要求可破坏性,这显然是一个 我们规范中的错误,以及未能实现实际的原件 意图。规范应该是在新的位置上进行的。
Daniel:在规范制定之初, 解决方案不能通过删除的破坏语义来完成 is_constructible。
is_constructible的设计也受到以前版本的影响 明确包含破坏语义的可构造概念, 因为在图书馆的概念化过程中 简化库中的约束,因为您不需要 一直添加Destructible。它经常被暗示但从未说过 在C ++ 03中实现。
纯构造语义也被认为是有用的,因此 HasConstructor确实也存在,并且肯定可以作为特征 好吧。
另一个经常被忽略的示例:这也会影响包装器 对,元组,数组等类型可能包含多个 类型:如果您认为T1已删除,这很容易理解 析构函数和T2具有可能抛出的构造函数:显然, 编译器可能需要在T1中使用T1的析构函数 std :: pair的构造函数,以确保核心语言 满足要求(所有先前完全构建的子对象 必须被破坏)。
核心语言在[class.copy] p11中也尊重这一事实:
如果X具有以下条件,则默认将类X的默认复制/移动构造函数定义为已删除(9.4.3 [dcl.fct.def.delete]):
[…]
—具有直接从对象中删除或无法访问的析构函数的任何直接或虚拟基类或非静态数据成员 默认的构造函数,
[…]Dave:特别是关于is_nothrow_constructible。事实 由于没有noexcept dtor而被挫败是一个缺陷。
它的结尾是:
维尔希望“进化小组”来研究这个问题。
从this gcc bug report起,至少gcc将等待问题解决。
另请参见Non-trivial destructor make class non-trivially-constructible,其中涵盖了有关相关问题的其他一些参考。另请注意clang bug for this。