默认定义的移动构造函数的noexcept规则是什么?

时间:2015-02-22 17:34:00

标签: c++ c++11 move-semantics pimpl-idiom noexcept

特别是与std::vector相关,在可能的情况下,noexcept类型的移动非常重要。

因此,在

中声明移动构造函数= default
struct Object1
{
    Object1(Object1 &&other) = default;
};

std::is_nothrow_move_constructible<Object1>::value将为true,因为Object1的每个成员(0都在这里)不是可移动构造的,而是here

然而,如果仅声明移动复制构造函数,然后在= default中定义,如下所示,会发生什么?

struct Object2
{
    Object2(Object2 &&other);
};
Object2::Object2(Object2 &&other) = default;

使用g ++ 4.9.2 std::is_nothrow_move_constructible<Object2>::valuefalse,我必须将声明和定义都标记为noexcept,以使其成为true

现在我感兴趣的是实际规则是什么。 特别是因为Effective Modern C++(Scott Meyers)中的第22项似乎通过建议实施像我Object2那样的pimpl-idiom移动构造函数来提供错误的建议。

1 个答案:

答案 0 :(得分:11)

[dcl.fct.def.default] / P2:

  

如果某个函数在其第一个声明中明确默认,

     
      
  • 如果隐式声明是和
  • ,则隐含地认为它是constexpr   
  • 它具有相同的异常规范,就好像它已被隐式声明(15.4)。
  •   

如果函数在后面的声明中明确默认,则不适用这些规则,如后面的示例所示,因此,除了析构函数之外,默认情况下该函数与大多数其他函数一样被视为noexcept(false)

由于显式默认值可以在不同的转换单元中 - 并且在pimpl情况下,在不同的TU中 - 编译器在看到类定义之后没有通用的方法是否移动构造函数将抛出,除非函数在类定义中明确默认(即,在其第一个声明时)。