std::move 的用法

Usages of std::move

问题下方是SO代码的简化版本。原代码:

SO的简化代码没有原来的结构,我只是用循环编造了数据。然而,仍然重要的细节是新结构的构造函数将被传递 std::vector。这些在循环中填充并移动到新结构

我突然想到,在制作新结构后将不需要 std::vector,因此 std::move 将是合适的。我在下面的代码中将用法标记为“移动 1”、“移动 2”、“移动 3”和“移动 4”:

#include <iostream>
#include <vector>

struct A {
    const int m_a;

    A() = delete;
    A(const int a_a) : m_a(a_a) {}

    void display() const { std::cout << "    " << m_a << "\n"; }
};

struct B {
    const std::vector<A> m_as;
    const int            m_b;

    B() = delete;
    B(
        std::vector<A>&& a_as,
        const int        a_b
    ) :
        m_as(std::move(a_as)), // Move 1
        m_b(a_b)
    {}

    void display() const {
        std::cout << "  " << m_b << ":\n";
        for (const A& a : m_as)
            a.display();
    }
};

struct C {
    const std::vector<B> m_bs1;
    const std::vector<B> m_bs2;

    C() = delete;
    C(
        std::vector<B>&& a_bs1,
        std::vector<B>&& a_bs2
    ) :
        m_bs1(std::move(a_bs1)), // Move 2
        m_bs2(std::move(a_bs2))  // Move 2
    {}

    void display() const {
        std::cout << "0:\n";
        for (const B& b : m_bs1)
            b.display();
        std::cout << "1:\n";
        for (const B& b : m_bs2)
            b.display();
    }
};

int main() {
    // Manually making up data, actual usage will take data from a different
    // kind of structure and populate vectors
    std::vector<B> bs1, bs2;
    for (int i = 0; i < 3; ++i) {
        std::vector<A> as;
        for (int j = 0; j < 2; ++j)
            as.emplace_back(j);
        bs1.emplace_back(std::move(as), i); // Move 3
    }
    for (int i = 0; i < 3; ++i) {
        std::vector<A> as;
        for (int j = 0; j < 2; ++j)
            as.emplace_back(j);
        bs2.emplace_back(std::move(as), i); // Move 3
    }

    C c(std::move(bs1), std::move(bs2)); // Move 4
    c.display();
    return 0;
}

一些假设:

问题: std::move 的所有用法都有意义还是没有必要?

您可以看到大部分 std::move 是必需的,只需删除它们,您的代码将无法编译。唯一的例外是 Move 1Move 2,代码在没有它们的情况下仍然可以编译,但这只是因为调用了 std::vector 复制构造函数。

如果您想从一个对象中移动,您几乎总是需要使用 std::move,唯一的例外是从临时对象中移动和返回对象时。