当前位置: 首页 > news >正文

Effective Modern C++ 条款31:避免使用默认捕获模式

避免使用默认捕获模式

  • 引言
  • 按引用捕获的危害
    • 示例:悬空引用的危险
  • 按值捕获的问题
    • 示例:按值捕获的误导
  • 显式捕获的好处
    • 示例:显式捕获的安全性
  • 成员变量的捕获
    • 示例:隐式捕获`this`指针
    • 解决方案:显式捕获成员变量
  • 总结

在C++11中,lambda表达式引入了两种默认捕获模式:按引用捕获([&])和按值捕获([=])。这两种模式虽然提供了便利,但也隐藏着潜在的风险。本文将深入探讨默认捕获模式的危害,并提供最佳实践建议,以帮助开发者编写更安全、更可靠的代码。

引言

默认捕获模式在C++中提供了极大的灵活性,但如果不加以注意,可能会导致悬空引用(dangling reference)或误导开发者认为lambda是独立的。这些潜在的问题可能在代码运行时引发未定义行为,影响程序的稳定性和正确性。

按引用捕获的危害

按引用捕获模式([&])允许lambda捕获其所在作用域内的所有局部变量和形参的引用。然而,这种模式可能导致悬空引用,因为引用的生命周期可能超过被引用对象的生命周期。

示例:悬空引用的危险

using FilterContainer = std::vector<std::function<bool(int)>>;void addDivisorFilter()
{auto calc1 = computeSomeValue1();auto calc2 = computeSomeValue2();auto divisor = computeDivisor(calc1, calc2);filters.emplace_back([&](int value) { return value % divisor == 0; });
}

在这个示例中,divisor是一个局部变量。当addDivisorFilter函数返回时,divisor的生命周期结束,而lambda捕获了对它的引用。如果之后使用这个lambda,将导致悬空引用,引发未定义行为。

按值捕获的问题

按值捕获模式([=])将lambda所在作用域内的所有局部变量和形参按值捕获。虽然这避免了悬空引用的风险,但它也可能带来误导,使开发者认为lambda是独立的,而实际上可能依赖外部变量。

示例:按值捕获的误导

void addDivisorFilter()
{static auto calc1 = computeSomeValue1();static auto calc2 = computeSomeValue2();static auto divisor = computeDivisor(calc1, calc2);filters.emplace_back([=](int value) { return value % divisor == 0; });++divisor;
}

在这个示例中,divisor是一个静态变量。尽管lambda使用了按值捕获模式,但它并没有捕获divisor,而是引用了静态变量。每次调用addDivisorFilter时,divisor都会递增,导致lambda的行为发生变化。这与开发者可能认为的按值捕获是独立的形成鲜明对比。

显式捕获的好处

显式捕获([variable][&variable])允许开发者明确指定lambda捕获的变量。这种做法提高了代码的可读性和维护性,并减少了潜在的错误。

示例:显式捕获的安全性

void addDivisorFilter()
{auto calc1 = computeSomeValue1();auto calc2 = computeSomeValue2();auto divisor = computeDivisor(calc1, calc2);filters.emplace_back([divisor](int value) { return value % divisor == 0; });
}

在这个示例中,divisor被显式捕获,确保其生命周期与lambda一致。这种做法避免了悬空引用的风险,并使代码更易于理解和维护。

成员变量的捕获

在类成员函数中,lambda可能会隐式捕获this指针。如果不加以注意,可能导致悬空指针。

示例:隐式捕获this指针

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

在这个示例中,divisorWidget类的成员变量。lambda隐式捕获了this指针,而不是divisor。如果Widget对象在lambda使用前被销毁,将导致悬空指针。

解决方案:显式捕获成员变量

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

在这个解决方案中,divisor被显式捕获并存储在divisorCopy中,确保其生命周期与lambda一致。

总结

默认捕获模式在C++中提供了便利,但如果不加以注意,可能导致悬空引用或误导开发者。显式捕获是一种更安全和可靠的做法,能够提高代码的可读性和维护性。在实际开发中,建议避免使用默认捕获模式,并显式指定lambda捕获的变量。

http://www.dtcms.com/a/439010.html

相关文章:

  • 找人做效果图去什么网站我想网站建设多少钱
  • Python 虚拟环境:venv 与 conda 该如何选择?
  • 公司名称大全好听宁波seo推荐
  • Windows逆向工程入门之整数类型
  • 怎么用wordpress做网盘google seo 营销网站
  • c2c网站类型可以翻外墙的浏览器
  • 1.HTTPS协议原理
  • 中山网站制作建设深圳网站设计 深圳市利
  • FontViewOK(字体管理软件) 多语便携版
  • Day90 基本情报技术者 单词表26 ソフトウェア品質管理
  • 腾讯开源啦,源码地址+部署脚本,工业级原生多模态
  • 参与网站网站建设连云港北京网站建设
  • 如何建设自己的网站 知乎wordpress 无广告视频插件
  • 算法 - FOC开环速度控制
  • 企业建设网站费用福建省建设厅网站信用评分
  • 北京私人做网站请seo的人帮做网站排名
  • 网站建设基础策划书网站做跳转会有什么影响
  • 网站建设怎么销售数据库网站
  • 做企业网站安装什么系统好google 网站优化工具
  • 网站内容分析阿里云备案网站建设方案书
  • 一键免费生成网页的网站wordpress做的外贸网站6
  • 域名注册网站那个好wordpress文字幻灯片
  • MySQL 8.0 InnoDB ReplicaSet 完整配置指南与切换
  • PCB学习——STM32F103VET6-STM32接口部分
  • [光学原理与应用-480]:《国产检测设备对比表》
  • 再谈Linux多进程——进程处理与守护进程
  • 广东平台网站建设制作大型网站只做要多少钱
  • 【LLM】基于ms-Swift大模型SFT和RL训练
  • 基于VisionMaster实现数据实时存储至MySQL
  • 文化共享工程网站建设情况做外贸比较好的网站