我正在努力理解这段代码,但是我无法弄清楚为什么这个版本
for (; first != last; ++first)
init = std::move(init) + *first;
比这个更快
for (; first != last; ++first)
init += *first;
我确实从std::accumulate中获取了它们。 第一个版本的汇编代码比第二个版本长。即使第一个版本创建了init的rvalue引用,它也总是通过添加*first来创建一个临时值,然后将其分配给init,这与第二种情况中创建临时值并将其分配给init的过程相同。那么,为什么使用std::move比使用+=运算符的“追加值”更好呢?
编辑
我正在查看C++20版本的accumulate代码,并且他们说在C++20之前,accumulate是这样的。
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是否有任何实际改进。
编辑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版本的accumulate使用std::move比没有使用它的版本更快呢?为什么在像字符串这样的东西中使用std::move会得到这样的改进,而不是使用像int这样的东西呢?为什么在这两种情况下,程序都创建了一个临时字符串str + b(或std::move(str) + b),然后移动到str?我的意思是,这是相同的操作。为什么第二个更快呢?
感谢您的耐心阅读,希望我这次表述清晰了。
std::accumulate
始终使用operator+()
或BinaryOperation
模板参数进行操作。 - Ruslanstd::accumulate
是一个模板,因此在查看汇编之前需要执行几个步骤。你能包含一个[mcve]吗? - 463035818_is_not_a_number