3

我跑了一些代码

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

我有个问题。为什么我们必须使用 std::move oninit即使initis int

4

3 回答 3

5

你是对的,移动一个int与复制它没有什么不同。

在这里,std::move只有当T's 的重载operator+对左值和右值表现不同时才会有用。

I've never heard of such classes, but I guess it could be useful for dynamic arrays that overload + in a clever way:

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

Edit: apparently std::string does a similar thing: its + reuses storage of one of the operands, if possible. (Thanks @FrançoisAndrieux and @Artyer.)

于 2020-04-16T20:33:05.987 回答
3

在isstd::move的情况下使用本身没有“需要” 。然而,由于我们可以认为基本意思是“请将此表达式转换为右值”,一个好的编译器在编译此代码时不应该引入任何开销。所以从这个意义上说,这段代码肯定会提高某些类型的性能,并且不太可能损害移动是无操作的类型的性能。Tintstd::moveTintT

于 2020-04-16T20:32:18.710 回答
1

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

即使init是int?

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

于 2020-04-16T20:27:43.630 回答