std :: переместить переменную, которая будет перезаписана - PullRequest
3 голосов
/ 16 апреля 2020

Я столкнулся с некоторым кодом

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 на init, даже если init равно int?

Ответы [ 3 ]

5 голосов
/ 16 апреля 2020

Вы правы, перемещение int ничем не отличается от его копирования.

Здесь std::move становится полезным, только если перегруженная T operator+ ведет себя по-разному для lvalues ​​и rvalues.

Я никогда не слышал о таких классах, но, полагаю, это может быть полезно для динамических c массивов, которые перегружают + умным способом:

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 делает то же самое: его + повторно использует память одного из операндов, если это возможно. (Спасибо @ FrancoisAndrieux и @Artyer.)

3 голосов
/ 16 апреля 2020

По сути, нет необходимости использовать std::move в случае, если T равно int. Однако, поскольку мы можем думать о std::move как о значении «пожалуйста, приведите это выражение к r-значению», хороший компилятор не должен вносить никаких накладных расходов при компиляции этого кода в случае, когда T является int. Таким образом, в этом смысле этот код определенно улучшит производительность для некоторых типов T, и маловероятно, что повредит производительности для типов, для которых перемещение запрещено.

1 голос
/ 16 апреля 2020

Мы не "должны" std::move init. Мы (или, скорее, стандартная библиотека в этом случае) делаем это, потому что перемещение может быть более эффективным, чем копирование для некоторых типов.

, даже если init - это int?

init не обязательно int. Это T, который является аргументом типа шаблона.

...