问题
I've being testing with GCC 5.2 and clang 3.6, both in C++14 mode, and they give the same output.
For the following code
#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;
}
the result 11 is obtained. But if uncomment the move assignment operator, the output becomes 01. How could an explicit noexcept specification on the move assignment operator possibly affect that of the move constructor?
回答1:
By defining the move assignment operator, you disabled the move constructor due to the rule of 5. The class isn't is_nothrow_move_constructible because it isn't move constructable at all, that constructor is no longer available unless you define it.
§12.8 Copying and moving class objects
If the definition of a class
Xdoes not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
—Xdoes not have a user-declared copy constructor,
—Xdoes not have a user-declared copy assignment operator,
—Xdoes not have a user-declared move assignment operator,
—Xdoes not have a user-declared destructor, and
— the move constructor would not be implicitly defined as deleted.
In the case where you had no user-defined move constructor, both were implicitly defined and followed the below specification.
§15.4 Exception specifications
An implicitly declared special member function shall have an exception-specification. If
fis an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-idTif and only ifTis allowed by the exception-specification of a function directly invoked byf’s implicit definition;fshall allow all exceptions if any function it directly invokes allows all exceptions, andfshall allow no exceptions if every function it directly invokes allows no exceptions.
回答2:
By declaring a move assignment, you've lost your implicit move constructor.
See the full chart below.
回答3:
The move constructor is simply not generated in this case - it has nothing to do with noexcept.
From 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&&).
回答4:
12.8/9:
If the definition of a class
Xdoes not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
Xdoes not have a user-declared copy constructor,
Xdoes not have a user-declared copy assignment operator,
Xdoes not have a user-declared move assignment operator, and
Xdoes not have a user-declared destructor.
By declaring a move assignment operator, you prevent the class from having any move constructor at all.
回答5:
By defining the move operator, you've suppressed the implicit move constructor. That's why std::is_nothrow_move_constructible fails. Provide it to get the desired output:
struct S {
S(S&&) noexcept {}
S& operator= (S&&) noexcept { return *this; }
};
来源:https://stackoverflow.com/questions/33057562/how-could-the-exception-specifier-on-move-assignment-operator-affect-that-of-mov