在C++ 11中使用lambda默认捕获值或引用的缺点?

Aja*_*dav 8 c++ lambda

在C++ 11 中使用value([=])或reference([&])使用lambda默认捕获有什么缺陷?

我知道一些陷阱,如:

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

按值划分的默认值是否有任何缺点?

Mik*_*eMB 9

我认为你提到的悬空参考问题是主要的陷阱.

然而,另一件有时被忽略的事情是,即使在成员函数中使用了按值捕获的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; 
}
Run Code Online (Sandbox Code Playgroud)

编辑:只是为了避免与@Snps相关的混淆:
如果bar是一个局部变量bas()(并因此被值捕获),上面的lambda将无法编译,因为by-value-captured-variables默认为const,除非您明确指定lambda为mutable.因此,如果您考虑一下,很明显bar不会被复制,但在阅读或编写代码时很容易被遗忘.


Bil*_*nch 5

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

int value(const T x) { ... }
int value(T& x) { ... }
Run Code Online (Sandbox Code Playgroud)


Snp*_*nps 5

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

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

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

[i = i] () mutable { ++i; }(); // Ok
Run Code Online (Sandbox Code Playgroud)