After constructing an object with a moving constructor, the new object should "steal" the resources of the "source" object, which is then left in an indefinite (but valid) state.
For example:
#include <iostream>
#include <vector>
template <class T>
void print(const std::vector<T>& v)
{
std::cout << "size = " << v.size() << " vector = ";
for (const auto& x : v)
std::cout << x << " ";
std::cout << std::endl;
}
int main()
{
std::vector<int> data(10, 3);
std::cout << "data:" << std::endl;
print(data);
std::vector<int> data2(std::move(data));
std::cout << "data2:" << std::endl;
print(data2);
std::cout << "data after moving:" << std::endl;
print(data);
return 0;
}
See it live on Coliru.
As far as I know the standard does not specify the content of data
after having called the moving constructor, however one would expect that the resources of data
have been stolen by data2
. And indeed, the output the program above shows that:
data:
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
data2:
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
data after moving:
size = 0 vector =
Now consider a slight variation of the above program:
#include <iostream>
#include <vector>
class A {
std::vector<int> m_data;
public:
A(std::vector<int>&& data) : m_data{data} { }
const std::vector<int>& data() const { return m_data; }
};
template <class T>
void print(const std::vector<T>& v)
{
std::cout << "size = " << v.size() << " vector = ";
for (const auto& x : v)
std::cout << x << " ";
std::cout << std::endl;
}
int main()
{
std::vector<int> data(10, 3);
std::cout << "data:" << std::endl;
print(data);
A x{std::move(data)};
std::cout << "x.data():" << std::endl;
print(x.data());
std::cout << "data after moving:" << std::endl;
print(data);
return 0;
}
See it live on Coliru.
I am surprised by output of the program:
data:
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
x.data():
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
data after moving:
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
It looks like the vector data
has been just copied to A::m_data
rather then being moved.
If I substitute the moving constructor of A with
A(std::vector<int>&& data) : m_data{std::move(data)} { }
(see it live on Coliru)
or with
A(std::vector<int>&& data) : m_data{std::forward<std::vector<int>&&>(data)} { }
(see it live on Coliru)
then the output of the program resembles that of the first code
data:
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
x.data():
size = 10 vector = 3 3 3 3 3 3 3 3 3 3
data after moving:
size = 0 vector =
In other words, it seems that either std:move
or std::forward
are necessary to effectively call the moving constructor of A::m_data
. Both std::move
and std::forward
return a static_cast
to std::vector<int>&&
, but the argument of the moving constructor of A
is already a rvalue.
Why is an additional std::move
or std::forward
necessary?