Reputation: 9512
This is my class and my program:
class A {
public:
int x;
int* v;
A() : x(5), v(new int[5]) {cout<<"default ctor. "; for (int i=0; i<x; i++) v[i]=rand()%10;}
A(const A& a) : x(a.x), v(new int[x]) {cout<<"copy ctor. "; for (int i=0; i<x; i++) v[i]=a.v[i]; }
A(A&& a) : x(a.x), v(a.v) {cout<<"move ctor. ";a.x=0;a.v=0;}
A& f() {return *this;}
A g() {return *this;}
};
int main() {
srand(time(0));
cout<<"A a --> ";A a;cout<<endl;
cout<<"A b(A()) --> ";A b(A());cout<<endl;
cout<<"A c(a.f()) --> ";A c(a.f());cout<<endl;
cout<<"A d(a.g()) --> ";A d(a.g());cout<<endl;
cout<<"A e(A().g()) --> ";A e(A().g());cout<<endl;
}
I would expect the objects b
, d
and e
to use the move constructor, however the output I get is:
A a --> default ctor.
A b(A()) -->
A c(a.f()) --> copy ctor.
A d(a.g()) --> copy ctor.
A e(A().g()) --> default ctor. copy ctor.
If in all three cases r-values are the arguments of the constructors, why isn't the move constructor being used?
Obviously I am compiling with the -std=c++11
option.
Upvotes: 1
Views: 75
Reputation: 171117
With b
, you've hit the "most vexing parse." b
is a function declaration, not an object.
Take the expression
A b(A());
Let's do some name changes and semantic-preserving transformations:
int foo(int (*p)());
Now, I think it's pretty clear that foo
is a function (returns int
and takes pointer to int()
function as parameter). Now substitute back A
for int
, b
for foo
and remember functions get implicitly converted to pointer-to-function. You'll see it's the same thing.
To get around this, you can use brace initialisation (thanks to @MikeSeymour for pointing that out):
A b{A()};
With d
, I think you're the "victim" of copy elision. The "copy ctor" output is probably from initialising the return value with *this
; the move from the return value to d
is completely elided.
With e
, it's the same story as d
.
Upvotes: 4