在我的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::的目的是什么?
您没有显示宏扩展到什么,但是我刚刚被提醒,当我昨天写了一个大加法的例子作为一个教训时,为什么这更有效。
二进制运算符创建并返回一个临时对象。对于适合机器寄存器的操作数,这可能是零成本的(最多将目标寄存器中之前的内容溢出到堆栈中),但有时需要创建大型数据结构。这似乎是实现该用例的模板代码。
然而,如果左操作数可以被重击,可以实现为
=
,覆盖操作数并优化新副本的创建。
正如我所提到的,这种编码风格让我觉得有点奇怪,=
的语义正是程序员在这里想要的,所以我不确定他们为什么不使用它。
init*first
的值类别无关紧要。
init*first
中的init
是左值。
因此,如果init*first
调用一个运算符
重载参数的值,它将导致该参数的复制构造
但是init*first
之后不再需要init
的值,因此将其移到参数中是有意义的。
类似地,操作符
重载通过右值引用获取其第一个参数,可用于允许操作修改参数。
这就是std::move
在这里实现的功能。
自C 20以来,该标准规定了这种行为。
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