C++ c++;为什么在移动构造函数时需要移动/前进

C++ c++;为什么在移动构造函数时需要移动/前进,c++,move-semantics,rvalue,C++,Move Semantics,Rvalue,在使用移动构造函数构造对象之后,新对象应该“窃取”“源”对象的资源,然后将其保留在不确定(但有效)状态 例如: #include <iostream> #include <vector> template <class T> void print(const std::vector<T>& v) { std::cout << "size = " << v.size() << " vector =

在使用移动构造函数构造对象之后,新对象应该“窃取”“源”对象的资源,然后将其保留在不确定(但有效)状态

例如:

#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;
}

现在考虑一下上面程序的细微变化:

#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 
看起来向量
数据
刚刚被复制到
A::m_data
而不是被移动

如果我用

A(std::vector<int>&& data) : m_data{std::move(data)} { }
换句话说,似乎需要
std:move
std::forward
来有效地调用
A::m_data
的移动构造函数。
std::move
std::forward
都将
static_cast
返回到
std::vector&
,但是
a
的移动构造函数的参数已经是右值


为什么需要额外的
std::move
std::forward
呢?

首先,您应该知道
A::A(std::vector&data)
意味着数据是对
std::vector
的右值引用,只是指引用而不是调用move构造函数


A(std::vector&data):m_data{data}{}
只是调用
m_data
的复制构造函数,因为
data
本身在
A::A
的范围内是一个命名值而不是
r值
临时值,因此
std::move
std::forward
是必要的。

或等
A(std::vector&data):m_data{data},m_data2{data}{}
是完全合法的,所以第一件事最好不要删除
数据
!!将
数据
用作表达式时,此表达式的类型将调整为非引用类型
std::vector
。没有
&
,没有
&
。编译器应该如何知道调用哪个构造函数?价值范畴<代码>数据具有左值类别,无法绑定到移动构造函数中的
std::vector&
。要更改值类别,请使用move:
std::move(data)
具有xvalue类别,并且可以绑定到
std::vector&
。这将是一个更好的匹配比复制。看看这听起来是否令人困惑。
A(std::vector<int>&& data) : m_data{std::move(data)} { }
A(std::vector<int>&& data) : m_data{std::forward<std::vector<int>&&>(data)} { }
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 =