c++ 使用std::vector移动语义

fivyi3re  于 2023-03-09  发布在  其他
关注(0)|答案(1)|浏览(223)

我有一个关于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已经被移动到bdata变量中。
现在,最大的问题是--为什么这个能起作用?
据我所知,A被移到了Buck构造函数的参数param中(因为我强制它是std::move()的右值,并且调用std::vector中的移动构造函数)。param本身应该是构造函数内的左值。那么,如果param是一个左值,data{param}究竟如何调用std::vector的move构造函数呢?

pdsfdshx

pdsfdshx1#

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)}; // 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

相关问题