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

What are the rules for noexcept on default defined move constructors?

特别是与 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++ 中的第 22 项(Scott Meyers)似乎给出了错误的建议,建议像我对 Object2.

那样实现 pimpl-idiom 移动构造函数

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

If a function is explicitly defaulted on its first declaration,

  • it is implicitly considered to be constexpr if the implicit declaration would be, and,
  • it has the same exception specification as if it had been implicitly declared (15.4).

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

由于显式默认设置可以在不同的翻译单元中——在 pimpl 的情况下,在不同的 TU 中——编译器没有通用的方法来确定之后仅查看 class 定义移动构造函数是否会抛出,除非该函数在 class 定义中明确默认(即在其第一个声明中)。