c++ - 标准算法按值采用 Lambda 是否有原因?

标签 c++ algorithm lambda pass-by-reference pass-by-value

<分区>

所以我在这里问了一个问题:Lambda Works on Latest Visual Studio, but Doesn't Work Elsewhere我得到的答复是,我的代码是自标准 25.1 [algorithms.general] 10 以来定义的实现:

Unless otherwise specified, algorithms that take function objects as arguments are permitted to copy those function objects freely. Programmers for whom object identity is important should consider using a wrapper class that points to a noncopied implementation object such as reference_wrapper<T>

我只是想知道发生这种情况的原因?我们一生都被告知要通过引用来获取对象,那么为什么标准是通过值来获取函数对象,甚至在我的链接问题中更糟糕的是复制这些对象?这样做有什么我不明白的优势吗?

最佳答案

std假定函数对象和迭代器可以自由复制。

std::ref提供了一种将函数对象转换为具有兼容 operator() 的伪引用的方法使用引用而不是值语义。因此不会丢失任何重要的东西。

如果您一生都被教导通过引用来获取对象,请重新考虑。除非有充分的理由,否则按值获取对象。关于值(value)的推理要容易得多;引用是指向程序中任何位置的任何状态的指针。

引用的常规用法,作为指向本地对象的指针,在使用它的上下文中没有被任何其他事件引用引用,这不是阅读您的代码的人或编译器可以假定的。如果您以这种方式推理引用,它们不会为您的代码增加可笑的复杂性。

但是,如果您以这种方式推理它们,那么当您的假设被违反时,您将遇到错误,并且它们将是微妙的、粗暴的、出乎意料的和可怕的。

一个典型的例子是 operator= 的数字。当 this 中断时并且参数引用同一个对象。但是任何接受两个相同类型的引用或指针的函数都会有同样的问题。

但即使是一个引用也会破坏您的代码。我们来看看sort .在伪代码中:

void sort( Iterator start, Iterator end, Ordering order )

现在,让我们将 Ordering 作为引用:

void sort( Iterator start, Iterator end, Ordering const& order )

这个怎么样?

std::function< void(int, int) > alice;
std::function< void(int, int) > bob;
alice = [&]( int x, int y ) { std:swap(alice, bob); return x<y; };
bob = [&]( int x, int y ) { std:swap(alice, bob); return x>y; };

现在,调用 sort( begin(vector), end(vector), alice ) .

每次<被称为,简称order对象交换意义。现在这很荒谬,但是当您使用 Ordering 时通过 const& ,优化器必须考虑到这种可能性,并在每次调用您的订购代码时将其排除!

您不会执行上述操作(事实上,此特定实现是 UB,因为它会违反 std::sort 上的任何合理要求);但编译器必须证明你没有做“那样”的事情(更改 ordering 中的代码)每次都遵循 order或调用它!这意味着不断重新加载 order 的状态,或者内联并证明你没有做出这样的疯狂行为。

在按值取值时执行此操作要困难一个数量级(并且基本上需要类似于 std::ref 的东西)。优化器有一个函数对象,它是本地的,它的状态也是本地的。存储在其中的任何内容都是本地的,编译器和优化器知道究竟谁可以合法修改它。

您编写的每个函数都采用 const&离开其“本地范围”(例如,称为 C 库函数)的那个不能假定 const& 的状态回来后还是一样。它必须从指针指向的任何地方重新加载数据。

现在,我确实说过按值传递,除非有充分的理由。并且有很多充分的理由;例如,您的类型移动或复制非常昂贵,这是一个很好的理由。您正在向其中写入数据。您实际上希望它在您每次阅读时都发生变化。等等

但默认行为应该是按值传递。只有在有充分理由的情况下才转向引用,因为成本是分散的并且很难确定。

关于c++ - 标准算法按值采用 Lambda 是否有原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41108386/

相关文章:

c++ - Karatsuba - 使用 CUDA 进行多项式乘法

algorithm - 设计一个数据结构来支持堆栈操作并找到最小值

algorithm - 如何从最小-最大堆中删除最大元素?

c++ - 传递给模板的 Lambda 未定义

c# - 使用 Lambda 获取不同的父项

c++ - 原子增量和返回计数器

c++ - 如何编写一个输入和输出均为std::variant的函数

c++ - 编译器如何在不更改参数列表的情况下重载模板函数?

java - 比较两个字符串的有效方法(字符顺序无关紧要)

c# - 通过特定属性从列表中删除另一个列表中的项目?