Я пытаюсь понять этот код, но не могу понять, почему эта версия
for (; first != last; ++first)
init = std::move(init) + *first;
быстрее, чем эта
for (; first != last; ++first)
init += *first;
Я взял их из std: : накапливать. Ассемблерный код первой версии длиннее второй. Даже если первая версия создает rvalue ref для init, она всегда создает временное значение, сначала добавляя *, а затем присваивая его init, это тот же процесс во втором случае, когда он создает временное значение, а затем назначает его init. Итак, почему использование std :: move лучше, чем «добавить значение» с оператором + =?
EDIT
Я смотрел код версии C ++ 20 для накопления, и они говорят, что до накопления C ++ 20 было это
template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init)
{
for (; first != last; ++first) {
init = init + *first;
}
return init;
}
и после C ++ 20 он становится
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 какое-либо реальное улучшение или нет.
EDIT2
Хорошо, вот мой пример кода:
#include <utility>
#include <chrono>
#include <iostream>
using ck = std::chrono::high_resolution_clock;
std::string
test_no_move(std::string str) {
std::string b = "t";
int count = 0;
while (++count < 100000)
str = std::move(str) + b; // Without std::move
return str;
}
std::string
test_with_move(std::string str) {
std::string b = "t";
int count = 0;
while (++count < 100000) // With std::move
str = str + b;
return str;
}
int main()
{
std::string result;
auto start = ck::now();
result = test_no_move("test");
auto finish = ck::now();
std::cout << "Test without std::move " << std::chrono::duration_cast<std::chrono::microseconds>(finish - start).count() << std::endl;
start = ck::now();
result = test_with_move("test");
finish = ck::now();
std::cout << "Test with std::move " << std::chrono::duration_cast<std::chrono::microseconds>(finish - start).count() << std::endl;
return 0;
}
Если вы запустите его, вы заметите, что версия std :: move действительно быстрее, чем другая, но если вы попробуете использовать встроенные типы вы получаете версию std :: move медленнее, чем другую.
Итак, мой вопрос заключался в том, что, поскольку эта ситуация, вероятно, такая же, как и для std :: accumulate, почему они говорят, что версия накопителя C ++ 20 с std :: move быстрее, чем версия без него? Почему, используя std :: move с чем-то вроде строк, я получаю такое улучшение, но не использую что-то вроде int? Зачем все это, если в обоих случаях программа создает временную строку str + b (или std :: move (str) + b), а затем переходит на str? То есть это та же операция. Почему второй быстрее?
Спасибо за терпение. Надеюсь, на этот раз я ясно выразился.