0

I was testing a move constructor and did the following:

#include <iostream>
#include <string>
using namespace std;

class X{
    public:
        int* p;
        int size;
        X(){}
        X(int n) : size(n){
            p = new int[n];
            for(int i = 0; i < n; i++)
                p[i] = i;
            cout << "Constructor\n";
        }
        ~X(){
            delete[] p;
        }
        X(const X& r){
            cout << "Copy\n";

        }
        X(X&& r){
            p = r.p;
            size = r.size;
            r.p = NULL;
            r.size = 0;
            cout << "Move\n";
        }
};
int main() {
    X a(10); //constructor    
    X b(a); // copy
    X c(X(3)); //constructor, move
    return 0;
}

What I expected in the output is in the comments, but when compiling (VS 2012) move constructor is not called?! But, if I add additional parameter to constructor:

string name;
X(int n, string _name) : size(n), name(_name){
    p = new int[n];
    for(int i = 0; i < n; i++)
        p[i] = i;
    cout << "Constructor\n";
}

and then

X a(10, "a"); //constructor
X b(a); // copy
X c(X(3, "pom")); //constructor, move

i get results as expected... I really don't understand why.

EDIT: Now tested on GCC 4.7.2 and it does not call Move constructor in both cases but C++ Builder XE5 compiler calls Move constructor in both cases. Yet, VS calls it only in the second case (when using additional constructor parameter). Very interesting...

9
  • Try using std::move. Commented Jul 11, 2014 at 13:22
  • I know about std::move but that doesn't answer my question. Commented Jul 11, 2014 at 13:22
  • 4
    It could be that the compiler is optimizing X c(X(3)) to turn it into X c(3). The compiler is allowed to do that. It's essentially a return-value optimization: Even before move semantics, if a function returns something by value to a caller who assigns to it, I believe the compiler is allowed to only allocate the variable once in its final location on the stack and "pretend" to return it. Commented Jul 11, 2014 at 13:36
  • 1
    Ben's hypothesis is solid. Best set a breakpoint at X c(X(3)) and have a look at the disassembly and/or try without any optimizations. Commented Jul 11, 2014 at 13:40
  • 2
    "When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects." [Such as debug output ;-)] (12.8/31 Copying and moving class objects) Commented Jul 11, 2014 at 14:06

1 Answer 1

7

The compiler is eliding the move construction and directly constructing X(3) into c, essentially turning your initialization into

X c(3);

With gcc, you can disable this using the -fno-elide-constructors switch. Once you add that, the output from your original example is as expected:

Constructor
Copy
Constructor
Move

Live demo

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.