std::move 一个即将被覆盖的变量

std::move a variable that is going to be overwritten

我 运行 上了一些 code

template<class InputIt, class T>
constexpr // since C++20
T accumulate(InputIt first, InputIt last, T init)
{
    for (; first != last; ++first) {
        init = std::move(init) + *first; // std::move since C++20
    }
    return init;
}

我有一个问题。为什么我们必须在 init 上使用 std::move,即使 initint

我们不会 "have" 到 std::move init。我们(或者更确切地说,本例中的标准库)这样做是因为对于某些类型,移动比复制更有效。

even if init is int?

init不一定是int。它是T,这是一个模板类型参数。

本身没有 "need,",在 Tint 的情况下使用 std::move。但是,由于我们可以认为 std::move 基本上意味着 "please cast this expression to an rvalue,",所以在 Tint 的情况下,一个好的编译器在编译此代码时不应引入任何开销。因此,从这个意义上说,这段代码 肯定会 提高某些类型的性能 T,并且 不太可能 损害某些类型的性能搬家是不行的。

你说得对,移动 int 与复制它没有什么不同。

这里,只有当 T 的重载 operator+ 对左值和右值的行为不同时,std::move 才有用。

我从未听说过这样的 类,但我想它可能对以巧妙的方式重载 + 的动态数组很有用:

struct Vec
{
    std::vector<int> elems;
};

// Returns a completely new vector.
Vec operator+(const Vec &a, const Vec &b)
{
    assert(a.size() == b.size());
    Vec ret(a.size());
    for (std::size_t i = 0; i < a.size(); i++)
        ret.elems[i] = a.elems[i] + b.elems[i];
    return ret;
}
// Reuses storage of `a`.
Vec operator+(Vec &&a, const Vec &b)
{
    assert(a.size() == b.size());
    for (std::size_t i = 0; i < a.size(); i++)
        a.elems[i] += b.elems[i];
    return std::move(a);
}
// Reuses storage of `b`.
Vec operator+(const Vec &a, Vec &&b)
{
    return std::move(b) + a;
}
// Reuses storage of `a`.
Vec operator+(Vec &&a, Vec &&b)
{
    return std::move(a) + b;
}

编辑: 显然 std::string 做了类似的事情:如果可能,它的 + 重用其中一个操作数的存储。 (感谢@FrançoisAndrieux 和@Artyer。)