特别是与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>::value
为false
,我必须将声明和定义都标记为noexcept
,以使其成为true
。
现在我感兴趣的是实际规则是什么。
特别是因为Effective Modern C++(Scott Meyers)中的第22项似乎通过建议实施像我Object2
那样的pimpl-idiom移动构造函数来提供错误的建议。
答案 0 :(得分:11)
[dcl.fct.def.default] / P2:
如果某个函数在其第一个声明中明确默认,
- 如果隐式声明是和
,则隐含地认为它是constexpr
- 它具有相同的异常规范,就好像它已被隐式声明(15.4)。
如果函数在后面的声明中明确默认,则不适用这些规则,如后面的示例所示,因此,除了析构函数之外,默认情况下该函数与大多数其他函数一样被视为noexcept(false)
。
由于显式默认值可以在不同的转换单元中 - 并且在pimpl情况下,是在不同的TU中 - 编译器在看到类定义之后没有通用的方法是否移动构造函数将抛出,除非函数在类定义中明确默认(即,在其第一个声明时)。