简体   繁体   English

在 std::accumulate 中使用 std::move

[英]Use of std::move in std::accumulate

In my Fedora 34 environment (g++), std::accumulate is defined as:在我的 Fedora 34 环境 (g++) 中, std::accumulate定义为:

template<typename ITER, typename T>
constexpr inline T accumulate(ITER first, ITER last, T init)
{
  for (; first != last; ++first)
      init = std::move(init) + *first; // why move ?

  return init;
}

If the expression init + *first is already an rvalue, what is the purpose of std::move ?如果表达式init + *first已经是一个右值,那么std::move的目的是什么?

The value category of init + *first doesn't matter. init + *first的值类别无关紧要。

init in init + *first is a lvalue. init init + *first中的 init 是一个左值。

So if init + *first calls an operator+ overload taking the parameter by-value, it will cause a copy construction of that parameter因此,如果init + *first调用按值传递参数的operator+重载,它将导致该参数的复制构造

But the value of init is not required anymore after init + *first , so it makes sense to move it into the parameter instead.但是在init + *first之后不再需要init的值,因此将它移到参数中是有意义的。

Similarly a operator+ overload taking its first argument by rvalue-reference might be used to allow modification of the argument by the operation.类似地,通过右值引用获取其第一个参数的operator+重载可用于允许操作修改参数。

This is what std::move achieves here.这就是std::move在这里实现的。

The standard specifies this behavior since C++20.该标准从 C++20 开始指定此行为。

std::move(init) + *first can sometimes generate more efficient code than init + *first , because it allows init to be overwritten. std::move(init) + *first有时可以生成比init + *first更高效的代码,因为它允许覆盖init However, since (as you observed) the result of the + will generally be an rvalue, there is no need to wrap the entire expression in a second std::move .但是,由于(如您所见) +的结果通常是右值,因此无需将整个表达式包装在第二个std::move中。

For example, if you are accumulating std::string s, then std::move(init) + *first might be able to append *first into reserved-but-not-yet-used space in init 's buffer instead of having to allocate a new buffer whose length is the sum of the lengths of init and *first .例如,如果您正在累积std::string s,那么std::move(init) + *first可能能够 append *first进入init缓冲区中保留但尚未使用的空间,而不是拥有分配一个新的缓冲区,其长度是init*first的长度之和。

You don't show what the macros expand to, but I was just reminded, when I wrote out an example of bignum addition yesterday as a lesson, why this is more efficient.您没有显示宏扩展为什么,但是当我昨天写了一个 bignum 加法示例作为课程时,我只是被提醒了,为什么这样做更有效。

The binary + operator creates and returns a temporary object.二进制+运算符创建并返回一个临时 object。 With operands that fit into a machine register, this can be zero-cost (at most spilling what was in the destination register before onto the stack), but sometimes, a large data structure will need to be created.对于适合机器寄存器的操作数,这可以是零成本(最多将之前目标寄存器中的内容溢出到堆栈上),但有时需要创建大型数据结构。 And this seems to be template code that might have to implement that use case.这似乎是可能必须实现该用例的模板代码。

If the left operand can be clobbered, though, + can be implemented as += , overwriting the operand and optimizing away the creation of a new copy.但是,如果可以破坏左操作数,则+可以实现为+= ,覆盖操作数并优化新副本的创建。

This coding style strikes me as a bit odd—as I mentioned, += has exactly the semantics the programmer seems to want here, so I'm not sure why they don't use that instead.这种编码风格让我觉得有点奇怪——正如我所提到的, +=正是程序员在这里想要的语义,所以我不确定他们为什么不使用它。

It's nothing to do with the return value of operator + , but with the arguments to it.这与operator +的返回值无关,而是与 arguments 相关。

As far as I can tell, a valid implementation of std::accumulate could be据我所知, std::accumulate的有效实现可能是

template<typename ITER, typename T, typename OP = plus>
constexpr inline T accumulate(ITER first, ITER last, T init, OP op = {})
{
  for (; first != last; ++first)
      init = op(std::move(init), *first); // move the argument that is being overwritten

  return init;
}

It would be a larger breaking change to specify accumulate in terms of operator += .根据operator +=指定accumulate将是一个更大的突破性变化。 For symmetry you'd want to change the BinaryOperation overloads, and that would break all the existing uses, as would any type that defined + but not += .为了对称,您需要更改BinaryOperation重载,这将破坏所有现有用途,任何定义+但未定义+=的类型也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM