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...
std::move.X c(X(3))to turn it intoX 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.