Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need some help understanding C++11 Move Constructors [duplicate]

As a C++ newbie I really have problems understanding the new Move-Constructor of C++11 and I hope someone can explain a specific situation I stumbled upon. Let's take this example code:

#include <iostream>

using namespace std;

class Model {
public:
    int data;
    Model(int data) : data(data) { cout << "Constructor" << endl; }
    Model(Model&& model) { cout << "Move constructor" << endl; }
    ~Model() { cout << "Destructor" << endl; }

private:
    Model(const Model& model);
    const Model& operator=(const Model&);

};

Model createModel(int data) {
    return Model(data);
}

int main(void) {
    Model model = createModel(1);
    cout << model.data << endl;
    return 0;
}

So I have created a createModel function which should return a model as a temporary rvalue and I want to assign it to an lvalue. I don't want the compiler to create copies of the Model object so I define the copy constructor as private and I do the same with the assignment operator to make sure no data is copied. After doing this the code correctly no longer compiles so I added the Move constructor and now it compiles again. But when I run the program I get this output:

Constructor
1
Destructor

So the Move Constructor was never called. I don't understand why I have to specify the move constructor to be able to compile the program when it is not used at all during runtime.

Is it because the compiler (GCC 4.8.2) optimizes the Move Constructor away? Or is there some other magic performed here?

So can someone please explain what exactly happens in the code above? The code does what I want but I really don't understand why.

like image 282
kayahr Avatar asked Jul 13 '14 11:07

kayahr


People also ask

What is the difference between move constructor and 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.

What is move constructor in C++ 11?

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

How do move constructors work?

A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy. An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.


1 Answers

There are two moves that could happen in your program:

  1. From the function to the return object.
  2. From the return object to model.

Both of these moves can be elided by the compiler for the same reason:

when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

There are other situations in which copy/move elision occurs (see §12.8/31 in C++11). Note that copy/move elision is entirely optional - the compiler doesn't have to do it.

Note that the compiler is allowed to optimize absolutely anything away as long as it doesn't change the behaviour of your program (under the as-if rule). The reason that copy/move elision is explicitly mentioned in the standard is because it might change the behaviour of your program if your copy/move constructors have side effects. The compiler is allowed to perform this optimization even if it changes the behaviour of your program. This is why your copy/move constructors should never have side effects, because then your program will have multiple valid execution paths.

You can pass the -fno-elide-constructors option to gcc to ensure that this optimization is never performed.

like image 96
Joseph Mansfield Avatar answered Nov 10 '22 00:11

Joseph Mansfield