标准算法是否有理由重视Lambda? [英] Is There a Reason Standard Algorithms Take Lambdas by Value?

查看:64
本文介绍了标准算法是否有理由重视Lambda?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在这里问了一个问题: Lambda可以在最新的Visual Studio上运行,但在其他地方无法使用得到的回应是,我的代码是自标准25.1 [algorithms.general] 10所说的实现以来定义的:

So I asked a question here: Lambda Works on Latest Visual Studio, but Doesn't Work Elsewhere to which I got the response, that my code was implementation defined since the standard's 25.1 [algorithms.general] 10 says:


除非另有说明,否则,以功能对象为参数,可以自由复制
这些功能对象。对于对象身份很重要的程序员,应考虑使用
包装器类,该包装器类指向未复制的实现对象,例如 reference_wrapper< T>

我只想知道为什么会这样吗?我们被告知一生要通过引用来获取对象,为什么标准会按值来获取函数对象,更糟糕的是在我链接的问题中复制这些对象?有这种方法我不理解的优点吗?

I'd just like a reason why this is happening? We're told our whole lives to take objects by reference, why then is the standard taking function objects by value, and even worse in my linked question making copies of those objects? Is there some advantage that I don't understand to doing it this way?

推荐答案

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

std assumes function objects and iterators are free to copy.

std :: ref 提供了一种方法使用兼容的 operator()将函数对象转换为伪引用,该引用使用引用而不是值语义。因此,没有任何重大价值的损失。

std::ref provides a method to turn a function object into a pseudo-reference with a compatible operator() that uses reference instead of value semantics. So nothing of large value is lost.

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

If you have been taught all your life to take objects by reference, reconsider. Unless there is a good reason otherwise, take objects by value. Reasoning about values is far easier; references are pointers into any state anywhere in your program.

引用的常规用法,作为指向本地对象的指针,本地对象在任何其他活动引用中均未引用使用它的上下文不是某人阅读您的代码,也不是编译器可以假定的。如果您以这种方式推理引用,则它们不会为您的代码增加可笑的数量。

The conventional use of references, as a pointer to a local object which is not referred to by any other active reference in the context where it is used, is not something someone reading your code nor the compiler can presume. If you reason about references this way, they don't add a ridiculous amount of complexity to your code.

但是,如果您以这种方式推理,您将违反您的假设时会出现错误,这些错误会变得微妙,严重,意外和可怕。

But if you reason about them that way, you are going to have bugs when your assumption is violated, and they will be subtle, gross, unexpected, and horrible.

一个经典的例子是运算符的数量= this 和参数引用同一对象时中断。但是任何使用两个引用或相同类型指针的函数都存在相同的问题。

A classic example is the number of operator= that break when this and the argument refer to the same object. But any function that takes two references or pointers of the same type has the same issue.

但是,即使是一个引用也会破坏您的代码。让我们看一下 sort 。用伪代码:

But even one reference can break your code. Let's look at sort. In pseudo-code:

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

现在,让我们订购一个参考:

Now, let's make Ordering a reference:

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 对象交换含义。现在,这非常荒谬,但是当您使用 const& Ordering 时,优化程序必须考虑到这种可能性并排除在每次订购代码调用时都可以排除!

Every time < is called, the referred-to order object swaps meaning. Now this is pretty ridiculous, but when you took Ordering by const&, the optimizer had to take into account that possibility and rule it out on every invokation of your ordering code!

您不会执行上述操作(实际上,此特定实现是UB,因为它会违反任何合理的要求在 std :: sort 上);但是编译器必须证明每次执行 排序更改代码)。 c $ c>或调用它!这意味着要不断重新加载 order 的状态,或者内联并证明您没有做过这种疯狂。

You wouldn't do the above (and in fact this particular implementation is UB as it would violate any reasonable requisites on std::sort); but the compiler has to prove you didn't do something "like that" (change the code in ordering) every time it follows order or invokes it! Which means constantly reloading the state of order, or inlining and proving you did nonesuch insanity.

按值计算要困难一个数量级(基本上需要 std :: ref 之类的东西)。优化器有一个函数对象,它是本地的,其状态是本地的。

Doing this when taking by-value is an order of magnitude harder (and basically requires something like std::ref). The optimizer has a function object, it is local, and its state is local. Anything stored within it is local, and the compiler and optimizer know who exactly can modify it legally.

您编写的每个函数都使用 const& 曾经离开其本地范围(例如,称为C库函数)不能假定 const& 的状态在此之后保持不变回来了它必须从指针指向的任何位置重新加载数据。

Every function you write taking a const& that ever leaves its "local scope" (say, called a C library function) can not assume the state of the const& remained the same after it got back. It must reload the data from wherever the pointer points to.

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

Now, I did say pass by value unless there is a good reason. And there are many good reasons; your type is very expensive to move or copy, for example, is a great reason. You are writing data to it. You actually want it to change as you read it each time. Etc.

但是默认行为应该是按值传递。仅在您有充分理由的情况下才转用引用,因为费用是分散的且难以确定。

But the default behavior should be pass-by-value. Only move to references if you have a good reason, because the costs are distributed and hard to pin down.

这篇关于标准算法是否有理由重视Lambda?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆