关于lambda表达式

基本语法就不谈了。

值捕获

  1. 值捕获就相当于在创建lambda对象时复制了一份所捕获的变量;
  2. 如果以传值的形式捕获外部变量,那么,lambda 体不允许修改外部变量;
  3. 可以使用mutable关键字打破2的限制: mutable { ... }
  4. this只能按值捕获,且访问this的成员不必使用this->语法,可以直接访问;
int a = 0;
auto test = [a]()  {
    cout << a << endl;
};
test();  // 0

a = 1;
test();  // 0

虽然可以用mutable让lambda中可以修改按值捕获的变量,但mutable也有它的问题,使用时要注意:

int a = 0;
auto test = [a]() mutable {
    cout << a << endl;
    a = 3;
};
test();  // 0
test();  // 3,这里a被修改过

引用捕获
引用捕获相当于函数传参时传了个引用,所以一定要注意变量生存期的问题;

int a = 0;
auto test = [&a]()  {
    cout << a << endl;
};
test();  // 0

a = 1;
test();  // 1

类的局部静态对象捕获是采用的引用方式捕获的,即使你使用了 [=] 来指定按值的方式捕获。

class test {
  public:
   static int x;
   void testtest() {
    auto test = [=]() {
        cout << x << endl;  // 注意x是类的static变量
        x = 5;
     };
     test();  // 0
     test();  // 5, 值已经在上一次执行时被修改了
   }
};
int test::x = 0;

Effective Modern C++ 条款31 对于lambda表达式,避免使用隐式捕获模式
鉴于对this、static类型变量捕获时的特殊情况,在Effective Modern C++中建议我们不要使用隐式捕获:隐式的引用捕获模式可能会导致悬挂引用,而使用隐式的值捕获模式诱骗你——让你认为你可以免疫刚说的问题(事实上没有免疫),然后它又骗你——让你认为你的闭包是独立的(事实上它们可能不是独立的)。
比如下面的例子:

class Widget {
public:
    ...          // 构造函数等
    void addFilter() const;  // 添加一个条目

private:
    int divisor;         // 用于Widget的过滤器中
};

void Widget::addFilter() const
{
    filters.emplace_back(
      [=](int value) { return value % divisor == 0; }
    );
}

可能你会认为,默认的值捕获使divisor已经被拷贝到闭包里,但其实不然,这里divisor是Widget类的成员,所以实际上捕获的是this,闭包内对divisor的使用会被编译器替换为this->divisor,所以就出现了闭包的生命周期可能会超出Widget实例的生存期。
所以如果根据这条建议,当我们写清楚每个变量的捕获方式,在这里试图用值捕获divisor时,编译器就会阻止我们,这有助于在更早的阶段发现问题。
那么这里的话,如果确实想捕获divisor的一个拷贝,可以这么写:

auto divisorCopy = divisor;          // 拷贝成员变量

filters.emplace_back(
  [=](int value)                // 捕获拷贝
  { return value % divisorCopy == 0; } //使用拷贝
);

如果在C++14里,还支持广义lambda捕获,即捕获的可以是表达式:

filters.emplace_back(               // C++14
  [divisor = divisor](int value)    // 在闭包中拷贝divisor
  { return value % divisor == 0; }  // 使用拷贝
);

你可能感兴趣的:(关于lambda表达式)