[Effective modern cpp] Lambda表达式

本文探讨了Lambda表达式的一些注意事项,强调避免使用默认捕获模式,因为可能会导致空悬行为。建议按需捕获,如按引用或按值,并注意捕获的生命周期。推荐使用初始化捕获和lambda式,而不是std::bind,因为lambda具有更好的可读性和效率。同时,介绍了如何通过decltype配合auto&&实现完美转发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

避免使用默认捕获模式

两种默认模式:引用按值

按引用捕获会导致空悬行为,如果使用,请保证引用变量的生命周期与lambda的生命周期一致。

  vector<std::function<bool(int)>> filters;
  void AddDivisorFilter(){
  	auto divisor = GetDivisor();
  	filters.emplace_back([&](int num){return num % divisor == 0})//对divisor的指涉可能空悬!
  }

按值捕获要注意如果捕获到指针(类的this指针)也会导致空悬行为, 捕获只能在创建lambda式的作用域内可见的非静态局部变量(包括形参)。

  class widget{
  public:
    ...
    void addFilter() const;
    void addFilter1() const;
  private:
    int divisor;
  };
  
  void widget::addFilter1(){
  	filters.emplace_back([](int num){return num % divisor == 0});//错误,没有可以捕获的divisor
  }
  
  void widget::addFilter(){
  	filters.emplace_back([=](int num){return num % divisor == 0});//这里divisor相当于 this->divisor
  }

使用默认值捕获模式,不是自洽的。静态存储期对象可以在lambda内使用,但是他们不能被捕获,但如果使用了默认值捕获模式,这些对象就会给人以错觉,认为它们可以加以捕获。

void addDivisorFilter()
{
  static auto divisor = GetDivisor();
  filters.emplace_back([=](int num){return num % divisor == 0})//未捕获到任何东西!divisor指涉到之前static 修饰的对象

  ++divisor;//意外修改了divisor  
}

使用初始化捕获将对象移入闭包

以下lambda表达式只能在c++14以上中使用,成为初始化捕获(广义lambda捕获)。
初始化捕获能完成c++11捕获中所有能完成的事情。
在lambda表达式[]中=左边的是闭包类的作用域,=右边的作用域与lambda式加以定义处的作用域。

class widget{
  ...
}

auto pw = std::make_unique<widget>();

auto func = [pw = std::move(pw)]{
			return pw->isValidated()
			       && pw->isArchived();};

在c++11中模拟初始化捕获的方法如下所示:

std::vector<double> data;
...
auto func = std::bind(
			  [](const std::vector<double>& data){
			  	....//数据操作
			  },std::move(data));

绑定对象包含传递给std::bind所有实参的副本。对于每个左值实参,在绑定对象内的对应的对象内对其实施复制构造,对于每个右值实参,则进行移动构造。

对auto&& 型别的形参使用decltype,从而实现完美转发

  auto f = [](auto&&... params)
  { return func(normalize(std::forward<decltype(params)>(params...)))};

优先使用lambda式,而非std::bind

std::bind无法绑定重载函数,需要进行强制转换

lambda可读性更好,表达力更强,可能运行的效率也更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值