【问题标题】:Disadvantage of using lambda default capture by value or reference in C++11?在 C++11 中按值或引用使用 lambda 默认捕获的缺点?
【发布时间】:2016-04-06 17:02:21
【问题描述】:

在 C++11 中使用 lambda 默认捕获按值 ([=]) 或按引用 ([&]) 有哪些缺陷?

我知道一些陷阱,例如:

  • 如果从 lambda 创建的闭包的生命周期超过局部变量的生命周期,闭包中的引用将悬空?

默认按值捕获有什么缺点吗?

【问题讨论】:

    标签: c++ lambda


    【解决方案1】:

    我认为你提到的悬空引用问题是主要缺陷。

    另外一件有时被忽略的事情是,即使在成员函数中使用按值捕获的 lambda,它也不会创建已使用成员变量的副本,而只会创建this 指针。

    首先,这意味着您再次面临悬空指针问题,其次,您可能会意外修改 lambda 范围之外的变量,即使看起来您只是在修改本地副本。

    例如这将打印 0 1 1 而不是 0 1 0

    struct Foo {
        int bar=0;
        int bas() {
            auto inc = [=]() {          
                bar++;  //this is equivalent to this->bar++ 
                return bar; 
            };
            return inc();
        }
    };
    
    int main() {
        Foo foo;
        std::cout << foo.bar <<" ";
        std::cout << foo.bas() << " ";
        std::cout << foo.bar << std::endl; 
    }
    

    编辑: 只是为了避免与@Snps 提出的观点相关的混淆:
    如果 barbas() 中的局部变量(因此被值捕获),则上述 lambda 不会编译,因为按值捕获的变量默认为 const,除非您明确指定 lambda 为可变。 所以如果你仔细想想,很明显 bar 不是复制的,但是在阅读或编写代码时很容易忘记。

    【讨论】:

    • 嗨迈克,谢谢你的回答,据我了解,捕获值类型成为闭包类的数据成员,引用不会成为闭包类的数据成员。请确认。
    • @Ajayyadav:嗯,它也变成了一个数据成员,但是是引用类型
    【解决方案2】:

    它的优点和缺点与以下之间的比较完全相同:

    int value(const T x) { ... }
    int value(T& x) { ... }
    

    【讨论】:

    • 好答案,我只想补充一点,lambdas 是对象。因此,当按值捕获时,重复使用 lambda 对象将使用它的内部状态。这与int value(const T x) { ... } 等函数的使用完全不同。如需参考,请参阅 - stackoverflow.com/questions/5501959/…
    • @Jendas:我不确定您的引用是否正确,但您是正确的,该值是在创建 lambda 时而不是在调用时捕获的。
    • 您好 Bill,感谢您的回答,默认值类型被捕获为 const 和引用类型非 const
    • 是的,它并没有完全解决问题,但它是我找到的关于 lambdas 内部状态的最接近的信息。
    【解决方案3】:

    使用[=][&lt;identifier&gt;] 按值捕获具有创建与捕获的实体完全相同类型的lambda成员的效果,包括常量,例如,当按值捕获 const int 时,即使 lambda 调用运算符是可变的,结果成员也不能被改变。

    const int i = 1;
    [=] () mutable { ++i; }(); // Error: increment of read-only variable.
    

    这可以使用 C++14 的初始化捕获表达式来解决:

    [i = i] () mutable { ++i; }(); // Ok
    

    【讨论】:

      【解决方案4】:

      按值捕获涉及复制已关闭的值,因此可能意味着该副本需要更多的内存消耗和更多的处理。

      【讨论】:

        猜你喜欢
        • 2014-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-03
        相关资源
        最近更新 更多