[使用移动的构造函数构造对象后,新对象应“窃取”“源”对象的资源,然后将其保留为不确定(但有效)状态。
例如:
#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;
}
据我所知,该标准在调用移动构造函数后未指定data
的内容,但是人们希望data
窃取了data2
的资源。实际上,上面程序的输出显示:
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 =
现在考虑上述程序的细微变化:
#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;
}
我对程序的输出感到惊讶:
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
似乎矢量data
刚刚被复制到A::m_data
而不是被移动。
如果将A的移动构造函数替换为
A(std::vector<int>&& data) : m_data{std::move(data)} { }
(查看live on Coliru)
或与
A(std::vector<int>&& data) : m_data{std::forward<std::vector<int>&&>(data)} { }
(查看live on Coliru)
然后程序的输出类似于第一个代码的输出
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 =
换句话说,似乎std:move
或std::forward
都是有效调用A::m_data
的移动构造函数所必需的。 std::move
和std::forward
都将static_cast
返回到std::vector<int>&&
,但是A
的移动构造函数的参数已经是一个右值。
为什么需要附加的std::move
或std::forward
?
首先,您应该知道A::A(std::vector<int>&& data)
表示数据是对std::vector<T>
的右值引用,仅表示引用不是对移动构造函数的调用,
A(std::vector<int>&& data) : m_data{data} { }
只是调用m_data
的副本构造函数,因为data
本身是一个命名值,而不是r value
范围内的A::A
临时值,因此std::move
或std::forward
是必需的。