C++ Lambda 表达式:通过 ref 开销捕获

Posted

技术标签:

【中文标题】C++ Lambda 表达式:通过 ref 开销捕获【英文标题】:C++ Lambda expressions: capture by ref overhead 【发布时间】:2019-10-03 11:30:25 【问题描述】:

我注意到在项目中我在很多地方工作,其中 lambda 表达式在此捕获指针,但不使用它。它会导致某种开销,例如指针复制,还是被编译器优化?

void MyClass::SomeFunction()

    ...
    grid->ForEachItem([this](const Item& item)
    
        // Some code doesn't use this
    

同样的问题专门用于通过引用捕获所有内容 [&]

【问题讨论】:

可能是,也可能不是。无论如何,它取决于下一个阅读它的开发人员,那么为什么要写它呢? 我敢打赌编译器会优化掉未使用的变量,但我不确定。无论哪种方式,我都不喜欢使用“this”和“&” lambda 捕获,因为这会带来麻烦和缺乏封装。另外,如果没有使用,为什么不直接删除它,因为它只会给阅读代码的人带来混乱? 我当然会删除它,但有趣的是它会导致一些开销。如果它使用,如果它只是一个指针副本 【参考方案1】:

我个人建议如果不使用this,则不要捕获它,但肯定不是因为性能原因。

我将从关于性能的强制性说明开始:首先编写代码以提高可读性。在您分析并确定一个真正的问题之后,您可以考虑优化代码中速度较慢的特定部分。当然,我说的不是算法复杂度,而是微优化

在 lambda 捕获的情况下,允许编译器不实际捕获未使用的对象,即使它们是通过副本 [=] 捕获的。最重要的是,lambda 主体对编译器是完全可见的,再加上 as if 规则,基本上可以确保在启用了优化的现代编译器上,您无需担心性能-明智地捕捉到什么。

但是,我建议不要捕获您不使用的内容的原因是为了表达的可读性和表现力。如果 lambda 使用 this 或任何其他变量作为引用或指针,您需要确保 lambda 不会超过它捕获的内容。例如,如果我看到一个捕获 this 并在方法之外返回的 lambda,我会非常紧张并特别注意确保捕获的对象在调用 lambda 之前不会过期。即使这不是问题(例如 lambda 不会逃逸到方法之外),读者的简单困惑(“这个 lambda 不应该使用对象的状态,为什么它会捕获 this? ") 足以成为一个令人信服的论据来避免它。

查看 lambda 的捕获列表时,您应该知道何时可以安全调用它。 lambda 谎言 如果它捕获了一个 ref 或一个指向它不使用的东西的指针。不要写撒谎的 lambda。


TLDR 没有开销,但出于可读性和表达性的原因不要这样做。

【讨论】:

感谢您的回答。顺便说一句,对于在外部调用的 lambda,我更喜欢通过 weak_from_this() 捕获一个可用于 enable_shared_from_this 类对象的星期指针,并在 lambda 或其他类型的仿函数仿函数中检查它。【参考方案2】:

是否会导致诸如指针复制之类的开销

就抽象机器而言:是的。会有一个指针拷贝,捕获的指针会增加lambda对象的大小。

但是如果编译器内联扩展函数调用,那么所有这些都可以优化为空。

同样的问题专门用于通过引用捕获所有内容 [&]

无论您使用值捕获还是引用捕获,捕获默认值都不会捕获 lambda 未使用的任何内容。

【讨论】:

以上是关于C++ Lambda 表达式:通过 ref 开销捕获的主要内容,如果未能解决你的问题,请参考以下文章

不能在 lambda 表达式中使用 ref 或 out 参数

如果“错误 CS1628:无法在匿名方法、lambda 或查询表达式中使用 in ref 或 out 参数”,如何在线程中使用 ref 参数?

c++基础(lambda)

转载C++ functionbind和lambda表达式

C++ lambda 表达式的生命周期是多少?

C++ std::priority_queue 使用 lambda 表达式