Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default move constructor vs. Default copy constructor vs. Default assignment operator

Tags:

c++

c++11

Why does C++ compiler have more restriction on automatically generated move constructors than on automatically generated copy constructor or assignment operator ?

Automatically generated move constructors are generated only if user has defined nothing (i.e: constructor, copy, assignment, destructor..)

Copy constructor or assignment operator are generated only if user has not defined respectively copy constructor or assignment operator.

I wonder why the difference.

like image 525
Guillaume Paris Avatar asked Mar 26 '13 10:03

Guillaume Paris


People also ask

What is the difference between a move constructor and a copy constructor?

If any constructor is being called, it means a new object is being created in memory. So, the only difference between a copy constructor and a move constructor is whether the source object that is passed to the constructor will have its member fields copied or moved into the new object.

Is copy constructor and default constructor same?

Unlike the default constructor, the body of the copy constructor created by the compiler is not empty, it copies all data members of the passed object to the object which is being created.

What is move constructor and assignment operator?

A move constructor is executed only when you construct an object. A move assignment operator is executed on a previously constructed object. It is exactly the same scenario as in the copy case.


2 Answers

I believe backwards compatibility plays a big part here. If the user defines any of the "Rule of three" functions (copy ctor, copy assignment op, dtor), it can be assumed the class does some internal resource management. Implicitly defining a move constructor could suddenly make the class invalid when compiled under C++11.

Consider this example:

class Res {   int *data;  public:   Res() : data(new int) {}    Res(const Res &arg) : data(new int(*arg.data)) {}    ~Res() { delete data; } }; 

Now if a default move constructor was generated for this class, its invocation would lead to a double deletion of data.

As for the move assignment operator preventing default move constructor definitions: if the move assignment operator does something other than default one, it would most likely be wrong to use the default move constructor. That's just the "Rule of three"/"Rule of five" in effect.

like image 106
Angew is no longer proud of SO Avatar answered Oct 18 '22 11:10

Angew is no longer proud of SO


As far as I know, this is because of downward compatibility. Consider classes written in C++ (before C++11) and what would happen if C++11 would start to automatically generate move-ctors in parallel to existing copy-ctors or generally any other ctor. It would easily break existing code, by-passing the copy-ctor the author of that class wrote. Hence, the rules for generating a move-ctor where crafted to only apply to "safe" cases.

Here's the article from Dave Abrahams about why implicit move must go, which eventually led to the current rules of C++11.

And this is an example how it would fail:

// NOTE: This example assumes an implicitly generated move-ctor  class X { private:         std::vector<int> v;  public:     // invariant: v.size() == 5     X() : v(5) {}      ~X()     {         std::cout << v[0] << std::endl;     } };  int main() {     std::vector<X> y;      // and here is where it would fail:     // X() is an rvalue: copied in C++03, moved in C++0x     // the classes' invariant breaks and the dtor will illegally access v[0].     y.push_back(X()); } 
like image 45
Daniel Frey Avatar answered Oct 18 '22 11:10

Daniel Frey