默认的移动构造函数是否被定义为noexcept?

89
似乎在重新分配元素时,向量会检查移动构造函数是否被标记为noexcept,然后决定是移动还是复制元素。默认的移动构造函数被定义为noexcept吗?我看到了下面的文档,但它没有指定这一点。http://en.cppreference.com/w/cpp/language/move_constructor 隐式声明的移动构造函数: 如果结构体、类或联合体的类型没有提供用户定义的移动构造函数,并且以下所有条件都成立:
- 没有用户声明的复制构造函数 - 没有用户声明的复制赋值运算符 - 没有用户声明的移动赋值运算符 - 没有用户声明的析构函数 - 隐式声明的移动构造函数由于下一节详细介绍的条件未定义为已删除
那么编译器将声明一个作为其类的内联公共成员的移动构造函数,其签名为T::T(T&&)。一个类可以有多个移动构造函数,例如T::T(const T&&)和T::T(T&&)。如果存在一些用户定义的移动构造函数,则用户仍然可以使用关键字default强制生成隐式声明的移动构造函数。
1个回答

94
我认为答案是15.4/14(异常规范):
继承构造函数(12.9)和隐式声明的特殊成员函数(第12条)具有异常规范。如果f是继承构造函数或隐式声明的默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符或移动赋值运算符,则其隐式异常规范仅在函数直接调用f的隐式定义的exception-specification允许type-id T时指定类型ID T;如果f直接调用的任何函数允许所有异常,那么f允许所有异常,并且如果它直接调用的每个函数都不允许任何异常,那么f具有异常规范noexcept(true)。
基本上,它做你想要的事情,隐式声明的移动构造函数只要可能就是noexcept。

64
额外信息: 你可以测试你的期望是否已经实现:static_assert(std::is_nothrow_move_constructible<MyType>::value, "MyType应为noexcept MoveConstructible"); - Howard Hinnant
1
因此,隐式特殊成员函数调用的所有函数必须声明为noexcept,才能使隐式特殊成员函数成为noexcept。这意味着您必须足够努力地标记所有相关函数为noexcept,这也意味着人为错误的空间很大,对吧? - mucaho
2
@mucaho:如果你的所有成员本身只使用隐式定义的特殊成员,那么这并不是很复杂。简单的规则是单一职责原则,而默认情况下你需要注意的人为错误只有显式定义特殊成员函数。这只留下了特定目的的类(例如unique_ptr)需要审核。 - Kerrek SB
13
如果有显式声明带有"default"的特殊成员函数,例如void T(T &&) = default,那会怎样呢?如果这个移动构造函数没有被其他条件阻止而隐式声明,比如用户定义了一个复制构造函数,那么我的理解是它的行为完全相同。 - Yan Zhou
4
是的,显式默认的特殊成员函数也遵循这些规则,除非为 constexprnoexcept 显式覆盖它们。不过你的例子中有一个多余的 void,所以会导致编译错误。 - Deduplicator
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接