Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In what scenarios should I expect to explicitly need to implement a move constructor and move assignment operator?

Given that a class actually is moveable, manually implementing the move constructor and move assignment operator for a class quickly become tedious.

I was wondering when doing so is actually a heavy, heavy, premature optimization?

For instance, if a class only has trivial POD data or members that themselves have move constructor and move assignment operator defined, then I'd guess that the compiler will either just optimize the shit out of the lot (in the case of PODs) and otherwise use the members' move constructor and move assignment operator.

But is that guaranteed? In what scenarios should I expect to explicitly need to implement a move constructor and move assignment operator?

EDIT: As mentioned below by Nicol Bolas in a comment to his answer at https://stackoverflow.com/a/9966105/6345, with Visual Studio 11 Beta (and before) no move constructor or move assignment operator is ever automatically generated. Reference: http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx

like image 950
Johann Gerell Avatar asked Apr 01 '12 15:04

Johann Gerell


People also ask

What is the purpose of a move constructor?

A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.

What is the difference between move constructor and move assignment?

The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.

Why and when do you need copy constructors Is there any situation where you want to only implement a copy constructor or an assignment operator but not both?

A user-defined copy constructor is generally needed when an object owns pointers or non-shareable references, such as to a file, in which case a destructor and an assignment operator should also be written (see Rule of three).

What are the scenarios when a copy constructor is called?

In C++, a Copy Constructor may be called for the following cases: 1) When an object of the class is returned by value. 2) When an object of the class is passed (to a function) by value as an argument. 3) When an object is constructed based on another object of the same class.


2 Answers

If you find yourself implementing, any of:

  • destructor
  • copy constructor
  • copy assignment

Then you should be asking yourself if you need to implement move construction. If you "= default" any of the above, you should be asking yourself if you should then also "= default" the move members.

Even more importantly, you should be documenting and testing your assumptions, for example:

static_assert(std::is_nothrow_default_constructible<A>::value, "");
static_assert(std::is_copy_constructible<A>::value, "");
static_assert(std::is_copy_assignable<A>::value, "");
static_assert(std::is_nothrow_move_constructible<A>::value, "");
static_assert(std::is_nothrow_move_assignable<A>::value, "");
static_assert(std::is_nothrow_destructible<A>::value, "");
like image 131
Howard Hinnant Avatar answered Dec 04 '22 17:12

Howard Hinnant


First, move semantics only help for classes that hold resources of any kind. "Flat" classes don't benefit from it at all.

Next, you should build your classes out of "building blocks", like vector, unique_ptr and the likes, that all deal with the nitty-gritty low-level detail of resources. If your class is done as such, you won't have to write anything at all since the compiler will generate the members correctly for you.

If you need to write a destructor for, say, logging, generation of move ctors will be disabled, so you need a T(T&&) = default; for compilers that support it. Otherwise, this is one of the only places were to write such a special member yourself (well, except if you write such a "building block").

Note that the logging in the destructor and constructor can be done an easier way. Just inherit from a special class that logs on construction / destruction. Or make it a member variable. With that:

tl;dr Let the compiler generate the special member for you. This also counts for copy constructor and assignment operator, aswell as the destructor. Don't write those yourself.

(Okay, maybe the assignment operators, if you can identify them as a bottle neck and want to optimize them, or if you want special exception safety or somesuch. Though, the "building blocks" should already provide all that.)

like image 28
Xeo Avatar answered Dec 04 '22 18:12

Xeo