移动赋值运算符的异常说明符如何影响移动构造函数的异常说明符?

3

我正在使用GCC 5.2和clang 3.6进行测试,均在C++14模式下运行,它们都产生了相同的输出。

对于以下代码

#include <iostream>
#include <type_traits>

struct S {
  // S& operator= (S&&) noexcept { return *this; }
};


int main() {
  std::cout << std::is_nothrow_move_constructible<S>::value
            << std::is_nothrow_move_assignable<S>::value;  
}

得到了结果11。但是如果取消注释移动赋值运算符,输出结果就变成了01。一个明确的noexcept规范如何影响移动构造函数的规范呢?

5个回答

7
通过定义移动赋值运算符,你禁用了移动构造函数,因为这违反了五法则。该类不是is_nothrow_move_constructible,因为它根本就无法移动构造,除非你定义它。 §12.8 复制和移动类对象

如果类X的定义没有显式声明移动构造函数,则只有在以下条件下才会被隐式声明为默认值:
X没有用户声明的复制构造函数,
X没有用户声明的复制赋值运算符,
X没有用户声明的移动赋值运算符,
X没有用户声明的析构函数,且
— 移动构造函数不会被隐式定义为已删除。

在没有用户定义移动构造函数的情况下,两者都将被隐式定义,并遵循以下规范。 §15.4 异常规格说明 一个隐式声明的特殊成员函数必须具有异常规范。如果f是隐式声明的默认构造函数、拷贝构造函数、移动构造函数、析构函数、拷贝赋值运算符或移动赋值运算符,则其隐式异常规范仅在T被函数直接调用的异常规范允许的情况下指定类型标识符T; 如果f直接调用的任何函数允许所有异常,则f应允许所有异常,如果f直接调用的每个函数都不允许任何异常,则f不应允许任何异常

5

通过声明移动赋值运算符,您已经失去了隐式移动构造函数。
请查看下面的完整图表。

enter image description here


好图表!顺便问一下,为什么那些默认字段是深红色的? - LogicStuff
因为它非常危险。 - Puppy
1
@LogicStuff 红色方块表示自 C++98/03 之后开始被弃用。在更新的标准中,我认为它们会变成“未声明”,但我不太确定是否有保证。在我的版本的 clang 中它们显示为未声明。 - Trevor Hickey
1
这是一个涉及到Howard Hinnant的线程,他是制作这个表格的人: https://dev59.com/VmAf5IYBdhLWcg3wukpkHoward的演讲: http://accu.org/content/conf2014/Howard_Hinnant_Accu_2014.pdf - Trevor Hickey
2
好图表!感谢提供链接。在C++11及以后的版本中,红色表示已弃用。它们尚未被删除,但可能会在未来的标准中被删除。指导方针:不要依赖已弃用的行为。如果您明确声明了析构函数、复制构造函数或复制赋值运算符中的任何一个,则应同时明确声明复制构造函数和复制赋值运算符。 - Howard Hinnant
显示剩余2条评论

2
在这种情况下,移动构造函数根本没有生成 - 这与noexcept无关。
来自cppreference的说明:
如果一个类类型(结构体、类或联合体)没有提供用户定义的移动构造函数,并且以下所有条件都成立:
- 没有用户声明的复制构造函数 - 没有用户声明的复制赋值运算符 - 没有用户声明的移动赋值运算符 - 没有用户声明的析构函数(直到C++14)
随后编译器将声明一个作为非显式内联公共成员的移动构造函数,其签名为T::T(T&&),而不是将其定义为已删除的移动构造函数。

2

12.8/9:

如果类 X 的定义没有显式声明移动构造函数,则只有在以下条件满足时才会隐式声明一个默认的移动构造函数:

  • X 没有用户声明的复制构造函数。

  • X 没有用户声明的复制赋值运算符。

  • X 没有用户声明的移动赋值运算符。

  • X 没有用户声明的析构函数。

通过声明移动赋值运算符,您可以防止该类具有任何移动构造函数。


1
通过定义移动操作符,您已经压制了隐式移动构造函数。这就是为什么std::is_nothrow_move_constructible失败的原因。提供它以获得所需的输出:
struct S {
  S(S&&) noexcept {}
  S& operator= (S&&) noexcept { return *this; }
};

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