Oleksiy
Oleksiy

Reputation: 39879

Is it safe to rely on an implicitly declared move constructor?

This is where I got most of this information: http://en.cppreference.com/w/cpp/language/move_constructor

Apparently these are the conditions for the implicitly generated move constructor to work:

My questions are:

  1. Is it safe to rely on implicit automatic move constructor?
  2. How do I check if it really worked instead of default copy constructor?
  3. Finally, and most importantly, is it a good idea and why? Or is it always better to define my own?

I am more inclined to follow the rule of three and manually create a destructor, a copy and move constructor, and a copy and move assignment operator, but I'm just curious about this implicit one.

Upvotes: 2

Views: 634

Answers (2)

Howard Hinnant
Howard Hinnant

Reputation: 219428

1. Is it safe to rely on implicit automatic move constructor?

Nothing is safe to rely upon without testing (implicit or explicit).

2. How do I check if it really worked instead of default copy constructor?

Testing. See the example test below.

3. Finally, and most importantly, is it a good idea and why? Or is it always better to define my own?

There are distinct (and growing) advantages to making your special members trivial. A trivial special member is one defined/supplied by the compiler. You can declare a trivial member with = default. Actually that last sentence is an exaggeration. If you declare a special member with = default, it won't for sure be trivial. That depends on your members and bases. But if you define a special member explicitly (as in C++98/03), then for sure it will not be trivial. If you have a choice between user-provided and trivial, prefer trivial.

Furthermore, you don't need to test if your type X has a move constructor. You need to test that if you move construct your X, that it has the right exception safety, and the right performance. If X::X(const X&) accomplishes that task, then so be it. In that case X::X(X&&) is not necessary.

If you expect that your type X will have a throwing copy constructor, and a much faster noexcept move constructor, here is a really nice test to confirm it is so:

static_assert(std::is_nothrow_move_constructible<X>::value,
                                "X should move construct without an exception");

Put this test right in your source/header. Now, no matter whether you implicitly, or explicitly declare or define your special members, you've got a concrete compile-time test that is practically zero cost. The static_assert generates zero code, and consumes a negligible amount of compile time.

Upvotes: 3

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154035

Here are the answers to your questions:

  1. What do you mean with "safe"? When the rules apply, i.e., the subobjects are movable and you didn't do anything to stomp on the generation of the move constructor, it will be created and used when present. Note, however, that it is easy to have a non-movable subobject which will somewhat invisibly inhibit the creation of a move constructor.
  2. To see if your class got a move constructor, just temporarily add an empty base logging when the copy and the move constructors are used and force the object to be moved/copied: it will log the correspondingly used constructor.
  3. No code is generally better than any code.

Upvotes: 5

Related Questions