当前位置: 首页 > 知识库问答 >
问题:

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

颜高朗
2023-03-14

在我的Fedora 34环境(g)中,std::acculate定义为:

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;
}

如果表达式init*first已经是右值,那么std::的目的是什么?


共有3个答案

葛承嗣
2023-03-14

您没有显示宏扩展到什么,但是我刚刚被提醒,当我昨天写了一个大加法的例子作为一个教训时,为什么这更有效。

二进制运算符创建并返回一个临时对象。对于适合机器寄存器的操作数,这可能是零成本的(最多将目标寄存器中之前的内容溢出到堆栈中),但有时需要创建大型数据结构。这似乎是实现该用例的模板代码。

然而,如果左操作数可以被重击,可以实现为=,覆盖操作数并优化新副本的创建。

正如我所提到的,这种编码风格让我觉得有点奇怪,=的语义正是程序员在这里想要的,所以我不确定他们为什么不使用它。

梁丘俊材
2023-03-14

init*first的值类别无关紧要。

init*first中的init是左值。

因此,如果init*first调用一个运算符重载参数的值,它将导致该参数的复制构造

但是init*first之后不再需要init的值,因此将其移到参数中是有意义的。

类似地,操作符重载通过右值引用获取其第一个参数,可用于允许操作修改参数。

这就是std::move在这里实现的功能。

自C 20以来,该标准规定了这种行为。

钱志义
2023-03-14

std::(init)*first有时可以生成比init*first更有效的代码,因为它允许覆盖init。但是,由于(正如您观察到的)的结果通常是右值,因此不需要在第二个std::移动中包装整个表达式

例如,如果您正在累积std::字符串s,那么std::移动(init)*first可能能够将*first附加到init的缓冲区,而不必分配一个长度为init*first长度之和的新缓冲区。

 类似资料:
  • 我在旧版本的C Cookbook中看到了这段代码,这让我很困惑。这似乎是编译,但我不知道为什么代码会这样写。 T()是什么意思?这是std::accumulate的init参数——开始求和的值。我编写了一个版本,其中我将double()替换为T()(以“硬连线”模板),然后它进行编译。double()是什么意思?

  • 我在理解条件变量及其在互斥体中的使用时遇到了一些困难,我希望社区能帮助我。请注意,我来自win32背景,因此与CRITICAL_SECTION、HANDLE、SetEvent、WaitForMultipleObject等一起使用。 这是我第一次尝试使用C++11标准库进行并发操作,它是在这里找到的一个程序示例的修改版本。 关于这个的几个问题。 我读过“任何要等待std::condition_var

  • 我在std::sort中发现了一个bug,特别是在一些QuickSort的实现中,我不知道问题是否出在一般的算法中。 精华: 当元素小于16时,所有的规范都被替换,因为std::sort使用插入排序。 当有17个或更多的元素时,使用快速排序,并从元素数量的对数限制递归深度,但向量在第一次__introsort_loop迭代时有时间恶化。 当有许多相同的元素时,就会出现向量损坏。用无效迭代器替换有效

  • 在“掌握C++17 STL”一书中,我看到iterator和const_iterator在一个类中实现,使用条件来减少代码重复 下面是我对简单数组类的实现(跳过数组类的大部分代码): 这段代码编译时没有错误,但iterator有点不可用: 给出错误: 我该如何使用那个迭代器呢?还是我应该从书上放弃这个想法呢?

  • 并行开发挺复杂的,特别是在试图用好线程和锁的过程中。如果要用到条件变量或std-atomics(一种无锁开发方式),那就更复杂了。C++0x提供了future和promise来简化任务线程间的返回值操作;同时为启动任务线程提供了packaged_task以方便操作。其中的关键点是允许2个任务间使用无(显式)锁的方式进行值传递;标准库帮你高效的做好这些了。基本思路很简单:当一个任务需要向父线程(启动

  • 标准库函数bind()和function()定义于头文件<functional>中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。bind()接受一个函数(或者函数对象,或者任何你可以通过”(…)”符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”或重新组织的函数对象。(译注:顾名思义,bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的。)例如: int