为什么我无法在 lambda 中捕获此副引用("&this")?

Why can't I capture this by-reference ('&this') in lambda?

本文关键字:引用 this lambda 为什么      更新时间:2023-10-16

我理解在lambda中捕获this(修改对象属性)的正确方法如下:

auto f = [this] () { /* ... */ };

但是我对我所看到的以下特点很好奇:

class C {
    public:
        void foo() {
            // auto f = [] () { // this not captured
            auto f = [&] () { // why does this work?
            // auto f = [&this] () { // Expected ',' before 'this'
            // auto f = [this] () { // works as expected
                x = 5;
            };
            f();
        }
    private:
        int x;
};

奇怪的是,我感到困惑(并希望回答)是为什么以下工作:

auto f = [&] () { /* ... */ }; // capture everything by reference

以及为什么我不能通过引用显式捕获this:

auto f = [&this] () { /* ... */ }; // a compiler error as seen above.

[&this]不工作的原因是因为它是语法错误。lambda-introducer中每个以逗号分隔的参数都是一个capture:

capture:
    identifier
    & identifier
    this

你可以看到&this在语法上是不允许的。不允许这样做的原因是,您永远不想通过引用捕获this,因为它是一个小的const指针。您可能只希望通过值传递它-因此语言不支持通过引用捕获this

要显式捕获this,您可以使用[this]作为lambda-introducer

第一个capture可以是capture-default,即

capture-default:
    &
    =

这意味着自动捕获我使用的任何内容,分别通过引用(&)或值(=) -然而this的处理是特殊的-在这两种情况下,它都是根据前面给出的原因按值捕获(即使默认捕获&,这通常意味着通过引用捕获)。

5.1.2.7/8:

用于名称查找(3.4),确定this(9.3.2)的类型和值并转换id-使用(*this)(9.3.1)将引用非静态类成员的表达式转换为类成员访问表达式,复合语句[OF the LAMBDA]在LAMBDA表达式的上下文中被考虑。

因此,当使用成员名时,lambda就像它是封闭成员函数的一部分一样(就像在您的示例中使用名称x一样),因此它将像成员函数一样生成this的"隐式用法"。

如果lambda-capture包含一个默认的capture-default为&,则lambda-capture中的标识符不能为前面是&。如果lambda-capture包含默认捕获值=,则lambda-capture不包含this和它所包含的每一个标识符之前都必须有&。标识符或this不能出现超过

因此,您可以使用[this], [&], [=][&,this]作为lambda-introducer来按值捕获this指针。

然而[&this][=, this]是病态的。在最后一种情况下,gcc宽容地警告[=,this], explicit by-copy capture of ‘this’ redundant with by-copy capture default而不是错误。

因为标准在捕获列表中没有&this:

N4713 8.4.5.2捕获:

lambda-capture:
    capture-default
    capture-list
    capture-default, capture-list
capture-default:
    &
    =
capture-list:
    capture...opt
    capture-list, capture...opt
capture:
    simple-capture
    init-capture
simple-capture:
    identifier
    &identifier
    this
    * this
init-capture:
    identifier initializer
    &identifier initializer
  • 对于lambda捕获的目的,表达式可能引用本地实体如下:

    7.3 A this表达式可能引用*this。

  • 因此,标准保证this*this有效,&this无效。另外,捕获this意味着通过引用捕获*this(它是一个左值,对象本身),而不是通过值捕获this指针 !