How could the exception specifier on move assignment operator affect that of move constructor?

坚强是说给别人听的谎言 提交于 2019-12-07 13:32:22

问题


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 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.

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 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.




回答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 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.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!