C++11/14/17 Lambda 引用捕获 [&] 不复制 [*this]

Imm*_*ant 2 c++ lambda copy this capture

请参阅此线程:https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0806r2.html

它说:

换句话说,一个默认捕获 ([&]) 以拼写出冗余的方式捕获 *this,但另一个捕获 ([=]) 以非冗余方式捕获它。

这表示在 c++17 之前,[=] 捕获this为值,而 [&] 将捕获 [*this],这是不明确的。所以我进行了一个快速测试,看看 [&] 是否默认捕获 [*this]。

我的测试代码尝试查看 [&] 默认捕获 *this,然后应该调用复制构造函数,并且对其值的任何更改都不会影响原始对象,因为它是副本。

#include<iostream>
using namespace std;
class M{
    int mI;
public:
    M() : mI(3) { cout << "ctor\n"; }
    ~M() { cout << "dtor\n"; }
    M(const M& m) {
        if (this != &m) {
            cout << "copy ctor\n";
            mI = m.mI;
        }
    }
    M& operator=(const M& m) {
        if (this != &m) {
            cout << "operator =\n";
            mI = m.mI;
        }
        return *this;
    }

    void CaptureByValue() {
        auto f1 = [=] () { // capture this
            cout << mI << '\n';
            ++(this->mI);
        };
        f1();
        cout << mI << '\n';
    }
    void CaptureByReference() {
        auto f1 = [&] () { // capture *this
            cout << mI << '\n';
            ++(this->mI);
        };
        f1();
        cout << mI << '\n';
    }
};

int main() {
    {
        M obj1;
        obj1.CaptureByValue();
    }
    cout << "------------\n";
    {
        M obj2;
        obj2.CaptureByReference();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译并运行它:

clang++ LambdaCapture.cpp -std=c++11 && ./a.out
clang++ LambdaCapture.cpp -std=c++14 && ./a.out
clang++ LambdaCapture.cpp -std=c++17 && ./a.out
Run Code Online (Sandbox Code Playgroud)

所有案例打印:

ctor
3
4
dtor
------------
ctor
3
4
dtor
Run Code Online (Sandbox Code Playgroud)

我的问题:

(1)结果超出了我的预期:没有调用任何复制构造函数CaptureByReference,并且更改的值影响了原始this对象。测试代码没有促进 cpp17 中的 lambda 语法更改。

(2) 我什至无法将捕获更改为 [=, *this] 或 [&, *this],因为编译器会说:

LambdaCapture.cpp:25:13: error: read-only variable is not assignable
            ++(this->mI);
            ^ ~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

很奇怪,这里怎么出来一个read-only变量,至于this指针。


感谢您的解释。

Ted*_*gmo 6

  • [=][this][=, this]以及所有按值[&, this]捕获。this也就是说,它复制了指针的值this
  • [&]*this通过引用捕获。也就是说,this在 lambda 中是一个指向*thislambda 外部的指针。

this因此,上述版本在 lambda 中的效果是相同的。

  • [=, *this]复制捕获的所有元素,并复制*this- 而不是this指针。
  • [&, *this]引用所有捕获的元素,但复制*this.
LambdaCapture.cpp:25:13: error: read-only variable is not assignable
            ++(this->mI);
            ^ ~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

这是因为 lambda 是const默认的。你需要创造它们mutable才能改变它们。

auto f1 = [&, *this]() mutable { // made mutable
    cout << mI << '\n';
    ++(this->mI);                // now ok
};
Run Code Online (Sandbox Code Playgroud)