C++ lambda表达式

少于 1 分钟阅读

C++11 中有两种捕获模式: 按引用和按值。按引用的默认捕获模式可能导致空悬引用,按值的默认捕获模式也无法对空悬引用免疫,而且会让你认为你的闭包是独立的(事实上它们可能不是独立的)。

按引用捕获会导致闭包包含指涉到局部变量的引用,或者指涉到定义lambda式的作用域内的形参的引用。一旦由lambda式所创建的闭包越过了该局部变量或形参的生命周期,那么闭包内的引用就会空悬。

std::vector<std::function<int(int)>> vec;

int f() {
  int divisor = 0;
  vec.push_back([&](int val){ return val / divisor;});
}

int f2() {
  auto lamdba = vec.at(0);
  lambda(1);  ///< 此处可能会出现空悬引用。
}

你可能会觉得如果把上面的按引用捕获换为按值捕获这样的空悬引用就不会出现。

  std::vector<std::function<int(int)>> vec;
class object {
public:
  int f() {
    int divisor = 0;
    vec.push_back([=](int val){ return val / divisor;});  ///< 这里是引用捕获
  }

  private:
  int  divisor = 0;
}

引用捕获只能针对于在创建lambda式的作用域内可见的非静态局部变量(包括形参);

上面代码等价于这样

class object {
public:
  int f() {
    int divisor = 0;
    vec.push_back([=](int val){ return val / divisor;});
    /// 等价于下面这句
    /// vec.push_back([this](int val){ return val / this->divisor;});
    /// 默认捕获列表捕获的是this的副本,而不是divisor的副本
  }

  private:
  int  divisor = 0;
}

lambda表达式同样不能捕获static变量, 在lambda表达式中使用static变量只能是按引用。

lambda 表达式与 std::bind 优先选用lambda

auto setSoundB = std::bind(setAlarm, steady_clock::now() + 1h, _1, 30s);

在创建setSoundB这函数对象的时候,通过std::bind去创建的时候steady_clock::now()已经进行了计算,而不是在调用时刻进行计算, 同样在具有函数重载的情况时,std::bind接收的只是函数名称无法参与函数重载的判断,会导致编译不过。

标签:

分类:

更新时间: