使用 std::vector 移动语义

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

我有一个关于 C++ 中移动语义的问题。看这个例子:

class Buck {
public:
    Buck(std::vector<int> param) : data{param} {}

    std::vector<int> data;
};

int main() {
    std::vector<int> A{1,2,3,4,5};
    Buck b{std::move(A)};
    std::cout << A.size() << std::endl;

    return 0;
}

这输出0,这意味着

A
已经被移动到
data
b
变量中。

现在,最大的问题 - 为什么这有效?

据我所知,

A
被移动到
param
构造函数的参数
Buck
中(因为我强制它成为带有
std::move()
的右值,并且调用了
std::vector
中的移动构造函数)。
param
本身应该是构造函数中的左值。那么,如果
data{param}
是左值,
std::vector
究竟如何调用
param
的移动构造函数?

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

A
被移动到
param
然后
param
被复制到
data
。您可以使用以下方法进行测试:

#include <iostream>

struct Data{
    Data() {
        std::cout << "init\n";
    }

    Data(Data const&) {
        std::cout << "copy\n";
    }

    Data(Data&&) {
        std::cout << "move\n";
    }
};

struct Buck {
    Buck(Data param): data{param} {} // copy

    Data data;
};

int main() {
    Data a;               // init
    Buck b{std::move(a)}; // move
}
init
move
copy

如果你想移动,你总是需要明确地转换为一个

rvalue
(例如通过
std::move
):

struct Buck {
    Buck(Data param): data{std::move(param)} {} // move

    Data data;
};

int main() {
    Data a;               // init
    Buck b{std::move(a)}; // move
}
init
move
move

如果想单次移动数据成员,可以在构造函数中取引用:

struct Buck {
    Buck(Data&& param): data{std::move(param)} {} // move

    Data data;
};

int main() {
    Data a;               // init
    Buck b{std::move(a)}; // call-by-reference
}
init
move

注意: 您仍然需要在成员初始化中显式

rvalue
-cast!如果您不使用它,您将复制一份:

struct Buck {
    Buck(Data&& param): data{param} {} // copy!!!

    Data data;
};

int main() {
    Data a;               // init
    Buck b{std::move(a)}; // call-by-reference
}
init
copy

std::move(a)
static_cast<Data&&>(a)
相同。当您使用
Data&&
类型的变量时,它被处理为
Data&
直到您在表达式中明确地将其转换为
Data&&
。声明一个变量为
Data&&
只对如何初始化它很重要,而不是如何使用它!


按值调用很有用,如果想要一个易于实现的复制和移动支持:

struct Buck {
    // param can be copied or moved, then it is moved to data
    Buck(Data param): data{std::move(param)} {}

    Data data;
};

int main() {
    Data a;               // init
    std::cout << "----\n";
    Buck b{a};            // copy
    std::cout << "----\n";
    Buck c{std::move(a)}; // move
}
init
----
copy
move
----
move
move

如果你想要最高性能,你可以通过同时实现复制和移动构造函数来避免第二次移动:

struct Buck {
    Buck(Data const& param): data{param} {}       // copy
    Buck(Data&& param): data{std::move(param)} {} // move

    Data data;
};

int main() {
    Data a;               // init
    std::cout << "----\n";
    Buck b{a};            // call-by-lvalue-reference
    std::cout << "----\n";
    Buck c{std::move(a)}; // call-by-rvalue-reference
}
init
----
copy
----
move
© www.soinside.com 2019 - 2024. All rights reserved.