2015-11-17 69 views
4

考虑一下:为什么我们需要捕获lambda参考的参考?

class TestLambda { 
public: 
    std::vector<char> data; 
}; 

void test_lambda(TestLambda& obj) { 
    [=]() mutable { 
     obj.data.push_back(0x01); 
    }(); 
} 

int main() { 
    TestLambda tst; 
    tst.data.push_back(0x99); 
    test_lambda(tst); 

    // tst.data is unchanged at this point 

    return 0; 
} 

调用test_lambda我所期待的是看到在tst.data变更后,但情况并非如此。要查看更改,我必须再次创建lambda传递参考obj,即。 [&obj]()

为什么我们需要这个?我的意思是,又是一个参考?

obj已经是参考。然后,lambda通过复制它来捕获obj。那么,obj以内lambda本身是不是一个参考?为什么?

有人可以解释我吗?谢谢。

+0

引用是一个别名,所以它只是另一个左值。在几乎所有情况下,它的行为与它所引用的变量没有区别。制作原件或别名的副本,其副本仍然是其副本。 – sp2danny

回答

5

当在分配的右侧使用时,引用就像“正常”变量一样工作。无论何时定义的值拉姆达捕获,拉姆达拥有外部变量的副本,仿佛拉姆达开始与这些行:

auto my_inner_variable = my_outer_reference; 
auto my_inner_other_variable = my_outer_other_variable; 

如果你想提到的“保持”的引用,你必须通过引用捕获它,从而告诉编译器发出这样的代码:

auto& my_inner_variable = my_outer_reference; 
auto& my_inner_other_variable = my_outer_other_variable; // if we instructed to capture everything by reference 
3

根据该标准草案§5.1.2/ P15 Lambda表达式[expr.prim.lambda]重点矿山):

的实体是通过拷贝捕获如果它是隐式捕获并且捕获默认= =或者如果它明确地被捕获 ,其形式不是&标识符或&标识符初始化器。 对于通过复制捕获的每个实体,在封闭类型中声明的未命名的非静态数据成员为 。这些成员 的声明顺序未指定。 这种数据成员的类型是对应捕获实体的类型,如果该实体不是对象的引用,或者是其他引用类型的引用。 [注意:如果捕获的 实体是对函数的引用,则对应的数据成员也是 也是对函数的引用。 - 结束注释]匿名 联盟的成员不得通过复制获取。

因此,在:

void test_lambda(TestLambda& obj) { 
    [=]() mutable { 
     obj.data.push_back(0x01); 
    }(); 
} 

obj被复制捕获,因此你理所当然所描述的结果。换句话说,这是标准规定的[=]捕获默认行为。

+0

如何“隐式”捕获obj? [](){}给我“未捕获”的错误。 +1。 –

+0

我认为OP明白'[=]'的含义。我认为这个问题是关于捕获实体的类型:为什么捕获的参考文件会复制一份。捕获可以被演示为:'auto objCopy = obj;'在lambda中,它应该是'TestLambda objCopy = obj;'还是'TestLambda&objCopy = obj;'? @Lodo的回答解决了这个问题,即使不完全清楚 –

+0

@AndyT正确。我的知识缺乏是在做TestLambda时发生了什么objCopy = obj;现在我明白了为什么它不能作为参考。 –

0

你的功能test_lambda包含嵌套lambda函数。在test_lambda内部,参考obj主要参考tst。然后你调用一个匿名的lambda函数,通过值来捕获。lambda函数obj内部是obj的副本,位于test_lambda内部。为什么不干脆写:

void test_lambda(TestLambda& obj) { 
    obj.data.push_back(0x01); 
} 

你现在正在做的

void test_lambda(TestLambda& obj) { 
    [=]() mutable { 
     objCopy.data.push_back(0x01); 
    }(); 
} 

其中objCopy被捕获的λ值创建或许说明。

+0

我写了这个片段以便能够表达我的问题。问题不在于如何编写函数来改变obj。 –