18 July 2022

C++ 核心指南目录

F.54: When writing a lambda that captures this or any class data member, don’t use [=] default capture

理由

违反此规则,会产生混乱不清的代码。在成员函数里用[=]捕获变量,看起来好像没问题。但是其实这种方式也会捕获到隐藏的 this 指针。而通过 this 指针是可以修改对象成员变量的。如果你通过 this 修改了对象成员变量,就相当于是进行了引用捕获。所以写代码的时候最好更明确一些。

例子

// -*- compile-command: "g++ -std=c++20 code.cpp && ./a"; -*-
#include <iostream>
#include <gsl/gsl>
using namespace std;
using namespace gsl;
class My_class {
    int x = 0;

    void f()
    {
        int i = 0;
        // ...

        auto lambda = [=] { use(i, x); };
        // BAD: "looks like" copy/value capture
        // [&] has identical semantics and copies the this pointer
        // under the current rules
        // [=,this] and [&,this] are not much better, and confusing

        x = 42;
        lambda(); // calls use(0, 42);
        x = 43;
        lambda(); // calls use(0, 43);

        // ...

        auto lambda2 = [i, this] { use(i, x); };
        // ok, most explicit and least confusing

        // ...
    }
};

注意

如果想要捕获成员数据的副本,可以考虑C++17的 [*this]

强化

如果 lambda 用了默认捕获,且可能会捕获到 this 指针。给代码打上一个警告标记。