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

Effective Modern C++ 条款32:使用初始化捕获将对象移入闭包

Effective Modern C++ 条款32:使用初始化捕获将对象移入闭包

  • 为什么需要移动捕获?
  • C++14的解决方案:初始化捕获
    • 基本用法示例
    • 直接初始化示例
  • C++11中的模拟实现
    • 方法1:手动实现函数对象
    • 方法2:使用std::bind模拟
    • std::unique_ptr的模拟示例
  • 关键要点总结
  • 结论

在C++开发中,lambda表达式已经成为现代C++编程不可或缺的一部分。然而,在C++11中,lambda捕获机制存在一个明显的限制:无法将对象移动(move)到闭包中。这个问题在C++14中通过"初始化捕获"(init capture)得到了解决。本文将深入探讨这一特性及其应用场景。

为什么需要移动捕获?

在C++11中,lambda表达式只能通过两种方式捕获外部变量:

  1. 按值捕获(复制)
  2. 按引用捕获(依赖外部生命周期)

这两种方式在某些场景下都不理想。考虑以下两种情况:

  1. 当你有一个只能被移动的对象(如std::unique_ptrstd::future)需要进入闭包时
  2. 当你要复制的对象复制开销很高,但移动成本很低(如标准库容器),而你希望移动而非复制该对象到闭包中

在C++11中,这两种需求都无法直接满足,这被认为是C++11的一个缺点。

C++14的解决方案:初始化捕获

C++14引入了初始化捕获(也称为通用lambda捕获)来解决这个问题。初始化捕获允许你:

  1. 指定从lambda生成的闭包类中的数据成员名称
  2. 指定初始化该成员的表达式

基本用法示例

auto pw = std::make_unique<Widget>();  // 创建Widgetauto func = [pw = std::move(pw)] {     // 使用std::move(pw)初始化闭包数据成员return pw->isValidated() && pw->isArchived();
};

在这个例子中:

  • =左侧的pw表示闭包类中的数据成员
  • =右侧的pw表示lambda上方声明的对象
  • pw = std::move(pw)表示"在闭包中创建数据成员pw,并使用将std::move应用于局部变量pw的结果来初始化该数据成员"

直接初始化示例

如果不需要在捕获前修改对象,我们可以直接初始化闭包成员:

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

C++11中的模拟实现

如果你的项目仍在使用C++11,有几种方法可以模拟移动捕获的效果。

方法1:手动实现函数对象

class IsValAndArch {
public:using DataType = std::unique_ptr<Widget>;explicit IsValAndArch(DataType&& ptr) : pw(std::move(ptr)) {}bool operator()() const {return pw->isValidated() && pw->isArchived();}private:DataType pw;
};auto func = IsValAndArch(std::make_unique<Widget>());

这种方法虽然代码量多,但能实现相同的功能。

方法2:使用std::bind模拟

更简洁的方法是使用std::bind

std::vector<double> data;auto func = std::bind([](const std::vector<double>& data) { /* 使用data */ },std::move(data)
);

这种方法的原理是:

  1. 将要捕获的对象移动到由std::bind产生的函数对象中
  2. 将被捕获对象的引用传递给lambda

对于mutable lambda,需要稍作修改:

auto func = std::bind([](std::vector<double>& data) mutable { /* 使用data */ },std::move(data)
);

std::unique_ptr的模拟示例

auto func = std::bind([](const std::unique_ptr<Widget>& pw) {return pw->isValidated() && pw->isArchived();},std::make_unique<Widget>()
);

关键要点总结

  1. C++14初始化捕获:使用初始化捕获可以方便地将对象移动到闭包中
  2. C++11替代方案
    • 通过手写类模拟初始化捕获
    • 使用std::bind来模拟初始化捕获
  3. 原理理解
    • 无法移动构造一个对象到C++11闭包
    • 但可以将对象移动构造进C++11的bind对象
    • 通过传引用将移动构造的对象传递给lambda

结论

初始化捕获是C++14中一个强大而灵活的特性,它解决了C++11 lambda表达式在移动语义方面的限制。对于仍在使用C++11的开发者,理解如何通过std::bind或手动实现函数对象来模拟这一功能同样重要。随着现代C++的发展,合理运用这些特性可以写出更高效、更清晰的代码。

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

相关文章:

  • 锦州网站建设预订鱼巴士设计师服务平台
  • 去哪找做网站的客户wordpress启动页
  • Python | 常见的几种编程模式
  • 向客户介绍网站建设的话本自己做的网站提示不安全吗
  • 【2024年莆田市校园创客节(小学组)初赛】期中考试
  • 【Java架构基础】DO、DTO、VO 都是干什么的?
  • 安装pandas报错No module named ‘encodings‘根本处理办法
  • 应届生招聘去哪个网站wordpress带投稿模板
  • 哪个公司的网站做的好秦皇岛网站制作的流程
  • 阳泉做网站多少钱wordpress move导入
  • 响应式网站下载网站上怎么做弹目提醒
  • 建设网站的心得体会设计logo去哪里找
  • AI开源应用:Pandas AI(一)
  • 【HarmonyOS 6】SpeechKit中的朗读控件,初始化前不进行窗口舞台的设置,也不会报错,与文档描述不符。
  • 大连旅游网站建设创建全国文明城市的目的
  • 【docker】运行对应服务
  • 做网站哪种编程语言最好公司响应式网站建设报价
  • 临沂网站建设中企动力58网站模板
  • 珠海品牌型网站建设网站设计怎么做链接
  • 哈尔滨无障碍网站建设ui培训费用
  • 如何在Ubuntu虚拟机中设置Samba共享,并在Windows宿主机中挂载为网络驱动器
  • 使用yopmail注册临时邮箱
  • 百度公司可以建设网站网页版哔哩哔哩怎么下载视频
  • 工厂弄个网站做外贸如何建立自己的网站平台的好处
  • 电力系统调度自动化的五遥: 遥信 遥测 遥控 遥调 遥视
  • 怎么做电影网站教程网站页面统计代码
  • 自建网站访问报错坊网站建设
  • 哪些网站可以做画赚钱网页设计学校模板
  • (四)自然语言处理笔记——Fasttext
  • 英集芯-IP5385 IIC通信异常原因深入分析及解决方案 21