Reputation: 1298
I have the following code:
#include <iostream>
#include <vector>
struct A
{
std::vector<int> x;
A()
{
std::cout << "A()" << std::endl;
}
A(const A&)
{
std::cout << "A(const A&)" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
};
struct B : public A
{
std::vector<int> y;
B()
{
std::cout << "B()" << std::endl;
}
B(const A&a)
{
std::cout << "B(const A&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const A&&a)
{
std::cout << "B(const A&&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const B&)
{
std::cout << "B(const B&)" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
};
A ret_a()
{
A a;
a.x.resize(10);
return a;
}
int main()
{
std::cout << "section I" << std::endl << std::endl;
A a = ret_a();
B b(a);
std::cout << "a.x.size=" << a.x.size() << std::endl;
std::cout << std::endl << "section II" << std::endl << std::endl;
B b2(ret_a());
std::cout << "b.x.size=" << b.x.size() << std::endl;
std::cout << std::endl << "section III" << std::endl << std::endl;
return 0;
}
With output (VS2013, Release build)
section I
A()
A()
B(const A&)
a.x.size=10
section II
A()
A()
B(const A&&)
~A()
b.x.size=10
section III
~B()
~A()
~B()
~A()
~A()
Why a.x.size() within "section I" has size 10? I thought that std::move should move all data from a.x to y.x
Why did "section II" call constructor A() twice? I thought that B(const A&&) would prevent excessive copying of A
UPDATE
see fixed code at http://pastebin.com/70Nmt9sT
Upvotes: 2
Views: 962
Reputation: 109159
Why
a.x.size()
within "section I" has size 10? I thought thatstd::move
should move all data froma.x
toy.x
This is because of B(const A&& a)
. Since a
is const
within that constructor, you only have const
access to its member x
, and calling std::move
on a vector<T> const
results in a vector<T> const&&
which cannot bind to vector
's move constructor (which takes a vector<T>&&
argument). Instead it ends up calling the copy constructor, which leaves the source object unmodified.
Why did "section II" call constructor
A()
twice? I thought thatB(const A&&)
would prevent excessive copying ofA
The first default construction occurs within the body of ret_a()
. The second default construction is that of the A
sub-object of B
. To avoid the second one move
the A
instance in the member initializer list.
B(const A&&a)
: A(std::move(a))
{
std::cout << "B(const A&&)" << std::endl;
y.resize(x.size());
}
Note that the move
doesn't actually result in moving the contents of a
due to the same reason as explained above. Moreover, even modifying the signature to B(A&& a)
would not result in the contents of a
being moved because the user provided copy constructor and destructor definitions prevent implicit generation of a move constructor for A
, and it'll be copied instead.
Upvotes: 2
Reputation: 16737
T&&
and const T&&
are not the same type. You almost never want a const
rvalue reference - you can't steal its resources since you made it const
! x = std::move(a.x);
in B(const A&a)
copies a.x
since the return type of std::move(a.x)
is const vector<int>&&
.B(const A&&)
calls the default constructor of A
since it is derived from A
, and the member initializer list does not make an attempt to construct the base A
. This is the second A
call. Upvotes: 4