Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the rules for noexcept on default defined move constructors?

Especially in connection with std::vector it is important that types are noexcept movable when possible.

So when declaring a move constructor = default like in

struct Object1
{
    Object1(Object1 &&other) = default;
};

std::is_nothrow_move_constructible<Object1>::value will be true as every member (0 here) of Object1 is nothrow-move-constructible, which is answered here.

Yet what happens if the move copy constructor is only declared and then later = default defined like in the following code?

struct Object2
{
    Object2(Object2 &&other);
};
Object2::Object2(Object2 &&other) = default;

With g++ 4.9.2 std::is_nothrow_move_constructible<Object2>::value is false and I have to mark both the declaration and the definition as noexcept to make it true.

Now what I am interested in is what the actual rules are. Especially since Item 22 in Effective Modern C++ (Scott Meyers) seems to give ill advice by suggesting to implement the pimpl-idiom move constructor like I did with Object2.

like image 296
mfuchs Avatar asked Feb 22 '15 17:02

mfuchs


People also ask

Is the default move constructor Noexcept?

Inheriting constructors and the implicitly-declared default constructors, copy constructors, move constructors, destructors, copy-assignment operators, move-assignment operators are all noexcept(true) by default, unless they are required to call a function that is noexcept(false) , in which case these functions are ...

Why does Noexcept move a constructor?

Tagging our move constructor with "noexcept" tells the compiler that it will not throw any exceptions. This condition is checked in C++ using the type trait function: "std::is_no_throw_move_constructible". This function will tell you whether the specifier is correctly set on your move constructor.

What does a default move constructor do?

For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.


1 Answers

[dcl.fct.def.default]/p2:

If a function is explicitly defaulted on its first declaration,

  • it is implicitly considered to be constexpr if the implicit declaration would be, and,
  • it has the same exception specification as if it had been implicitly declared (15.4).

These rules do not apply if the function is explicitly defaulted on a later declaration, as in your later example, so instead, except for destructors, the function is considered noexcept(false) by default like most other functions.

Since the explicit defaulting can be in a different translation unit - and in the pimpl case, is in a different TU - there's no general way for the compiler to figure out after seeing the class definition only whether the move constructor will throw, unless the function is explicitly defaulted in the class definition (i.e., at its first declaration).

like image 62
T.C. Avatar answered Oct 22 '22 01:10

T.C.