Я пытаюсь понять этот код, но не могу понять, почему эта версия
for (; first != last; ++first)
init = std::move(init) + *first;
быстрее, чем это
for (; first != last; ++first)
init += *first;
Я взял их из std::accumulate. Ассемблерный код первой версии длиннее второй. Даже если первая версия создает ссылку rvalue для init, она всегда создает временное значение, добавляя *first, а затем назначая его init, то есть тот же процесс во втором случае, когда он создает временное значение, а затем назначает его init. Итак, почему использование std::move лучше, чем «добавление значения» с оператором +=?
РЕДАКТИРОВАТЬ
Я просматривал код 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;
}
и после С++ 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 какое-либо реальное улучшение или нет.
РЕДАКТИРОВАТЬ2
Хорошо, вот мой пример кода:
#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), а затем перемещается в строку? То есть это одна и та же операция. Почему второй быстрее?
Спасибо за терпение. Надеюсь, на этот раз я ясно выразился.
init
, если этот тип не реализует какую-либо перегрузку с помощью ссылки rvalue, этот случай будет таким же, поэтому, пожалуйста, предоставьте полный пример - person Alberto Sinigaglia   schedule 16.06.2020std::accumulate
всегда работает либо с использованиемoperator+()
, либо с использованием параметра шаблонаBinaryOperation
. - person Ruslan   schedule 16.06.2020std::accumulate
— это шаблон, поэтому необходимо выполнить несколько шагов, прежде чем вы сможете взглянуть на сборку. Можете ли вы включить минимально воспроизводимый пример? - person 463035818_is_not_a_number   schedule 16.06.2020