为什么我们需要捕获lambda中引用的引用?

时间:2015-11-17 11:06:43

标签: c++ c++11 lambda pass-by-reference

考虑一下:

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本身不是参考?为什么呢?

有人可以解释一下吗?谢谢。

3 个答案:

答案 0 :(得分:5)

当在分配的右侧使用时,引用的作用与正常情况相同。变量。每当你通过值定义lambda捕获时,lambda拥有外部变量的副本,就像lambda以这些行开头一样:

auto my_inner_variable = my_outer_reference;
auto my_inner_other_variable = my_outer_other_variable;

如果您希望引用&#34;保留&#34;一个引用,你必须通过引用捕获它,从而指示编译器发出如下代码:

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

答案 1 :(得分:3)

根据标准草案§5.1.2/ p15 Lambda表达式[expr.prim.lambda] Emphasis Mine ):

  

如果隐式捕获实体并且捕获默认值为=,或者通过捕获显式捕获实体,则按副本捕获实体   这不是形式&amp;标识符或&amp;标识符初始化程序。   对于由副本捕获的每个实体,未命名的非静态数据成员是   在闭包类型中声明。这些成员的声明顺序   没有具体说明。 此类数据成员的类型是   如果实体不是对a的引用,则对应的捕获实体   对象,否则引用的类型。 [注意:如果捕获   entity是对函数的引用,对应的数据成员是   也是对函数的引用。 - 尾注]匿名成员   工会不得以副本为准。

因此,在:

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

obj由副本捕获,因此您可以正确地获得所描述的结果。换句话说,这是标准规定[=]捕获默认值的行为。

答案 2 :(得分:0)

您的函数test_lambda包含嵌套的lambda函数。在test_lambda内,参考obj在主要内容中引用tst。然后你调用一个按值捕获的匿名lambda函数。 lambda函数obj内部是test_lambda内的obj的副本。为什么不简单写一下:

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

您现在正在做的事情可能由

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

其中objCopy是由捕获lambda的值创建的。