移动赋值运算符的异常说明符如何影响移动构造函数的异常说明符?
How could the exception specifier on move assignment operator affect that of move constructor?
我在 C++14 模式下使用 GCC 5.2 和 clang 3.6 进行测试,它们提供相同的输出。
对于下面的代码
#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
规范如何影响移动构造函数的规范?
通过定义移动运算符,您已经取消了隐式移动构造函数。这就是 std::is_nothrow_move_constructible
失败的原因。提供它以获得所需的输出:
struct S {
S(S&&) noexcept {}
S& operator= (S&&) noexcept { return *this; }
};
在这种情况下根本不会生成移动构造函数 - 它与 noexcept
.
无关
来自 cppreference:
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
- there are no user-declared copy constructors
- there are no user-declared copy assignment operators
- there are no user-declared move assignment operators
- there are no user-declared destructors
(until C++14)
the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section
then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).
12.8/9:
If the definition of a class X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
X
does not have a user-declared copy constructor,
X
does not have a user-declared copy assignment operator,
X
does not have a user-declared move assignment operator, and
X
does not have a user-declared destructor.
通过声明移动赋值运算符,您可以防止 class 有任何移动构造函数。
通过定义移动赋值运算符,由于 rule of 5,您禁用了移动构造函数。 class 不是 is_nothrow_move_constructible
因为它根本不是可移动构造的,除非您定义它,否则该构造函数不再可用。
§12.8 复制和移动 class 对象
If the definition of a class X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
— X
does not have a user-declared copy constructor,
— X
does not have a user-declared copy assignment operator,
— X
does not have a user-declared move assignment operator,
— X
does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.
在您没有用户定义的移动构造函数的情况下,两者都被隐式定义并遵循以下规范。
§15.4 异常规范
An implicitly declared special member function shall have an exception-specification. If f
is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T
if and only if T
is allowed by the exception-specification of a function directly invoked by f
’s implicit definition; f
shall allow all exceptions if any function it directly invokes allows all exceptions, and f
shall allow no exceptions if every function it directly invokes allows no exceptions.
通过声明移动赋值,您丢失了隐式移动构造函数。
请参阅下面的完整图表。
我在 C++14 模式下使用 GCC 5.2 和 clang 3.6 进行测试,它们提供相同的输出。
对于下面的代码
#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
规范如何影响移动构造函数的规范?
通过定义移动运算符,您已经取消了隐式移动构造函数。这就是 std::is_nothrow_move_constructible
失败的原因。提供它以获得所需的输出:
struct S {
S(S&&) noexcept {}
S& operator= (S&&) noexcept { return *this; }
};
在这种情况下根本不会生成移动构造函数 - 它与 noexcept
.
来自 cppreference:
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
- there are no user-declared copy constructors
- there are no user-declared copy assignment operators
- there are no user-declared move assignment operators
- there are no user-declared destructors (until C++14)
the implicitly-declared move constructor is not defined as deleted due to conditions detailed in the next section then the compiler will declare a move constructor as a non-explicit inline public member of its class with the signature T::T(T&&).
12.8/9:
If the definition of a class
X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
X
does not have a user-declared copy constructor,
X
does not have a user-declared copy assignment operator,
X
does not have a user-declared move assignment operator, and
X
does not have a user-declared destructor.
通过声明移动赋值运算符,您可以防止 class 有任何移动构造函数。
通过定义移动赋值运算符,由于 rule of 5,您禁用了移动构造函数。 class 不是 is_nothrow_move_constructible
因为它根本不是可移动构造的,除非您定义它,否则该构造函数不再可用。
§12.8 复制和移动 class 对象
If the definition of a class
X
does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
—X
does not have a user-declared copy constructor,
—X
does not have a user-declared copy assignment operator,
—X
does not have a user-declared move assignment operator,
—X
does not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.
在您没有用户定义的移动构造函数的情况下,两者都被隐式定义并遵循以下规范。
§15.4 异常规范
An implicitly declared special member function shall have an exception-specification. If
f
is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-idT
if and only ifT
is allowed by the exception-specification of a function directly invoked byf
’s implicit definition;f
shall allow all exceptions if any function it directly invokes allows all exceptions, andf
shall allow no exceptions if every function it directly invokes allows no exceptions.
通过声明移动赋值,您丢失了隐式移动构造函数。
请参阅下面的完整图表。