c ++为什么在移动构造函数中需要向前/向后移动

问题描述 投票:0回答:1

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

例如:

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

查看live on Coliru

据我所知,该标准在调用移动构造函数后未指定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;
}

查看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 = 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:movestd::forward都是有效调用A::m_data的移动构造函数所必需的。 std::movestd::forward都将static_cast返回到std::vector<int>&&,但是A的移动构造函数的参数已经是一个右值。

为什么需要附加的std::movestd::forward

c++ move-semantics rvalue
1个回答
0
投票

首先,您应该知道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::movestd::forward是必需的。

© www.soinside.com 2019 - 2024. All rights reserved.