【Effective Modern C++】第六章 lambda表达式:32. 使用初始化捕获来移动对象到闭包

📅 发布时间:2026/7/15 21:29:11 👁️ 浏览次数:
【Effective Modern C++】第六章 lambda表达式:32. 使用初始化捕获来移动对象到闭包
C11 lambda 的捕获短板我们知道 C11 的 lambda 只有按值捕获和按引用捕获两种方式但这两种方式都有局限满足不了一些特殊场景对于只能移动、不能拷贝的对象比如std::unique_ptr、std::futureC11 根本没法把它们放进闭包对于拷贝成本很高的对象比如大容器std::vector我们只想移动进闭包节约开销C11 也做不到只能被迫拷贝。这是 C11 lambda 设计上的一个明显缺陷而 C14 直接补上了这个短板。C14 的完美解决方案初始化捕获init captureC14 引入了初始化捕获也叫通用 lambda 捕获它的灵活性极强移动捕获只是它的核心用法之一甚至能直接在捕获里创建对象完全覆盖了 C11 捕获的功能还能做更多事。1. 初始化捕获的语法逻辑[闭包内的数据成员名 初始化表达式]等号左侧是 lambda 闭包类里自定义的数据成员名称等号右侧是初始化这个成员的表达式可以是移动、函数调用、临时对象等。两者作用域不同左侧属于闭包类右侧是 lambda 定义的外部作用域。2. 两种经典使用场景把已有对象移动进闭包auto pw std::make_uniqueWidget(); // 将pw移动到闭包中而非拷贝 auto func [pw std::move(pw)] { return pw-isValidated() pw-isArchived(); };直接在捕获里创建对象连局部变量都不用auto func [pw std::make_uniqueWidget()] { return pw-isValidated() pw-isArchived(); };C11 没有初始化捕获两种模拟移动捕获的方法如果编译器只支持 C11没法用初始化捕获也能实现近似的移动捕获效果。1. 手写仿函数类lambda 本质就是编译器生成的闭包类那我们可以手动写一个类在构造函数里把对象移动到成员变量中重载operator()实现 lambda 的逻辑效果完全一致。2. 用std::bind模拟更实用、更常用这是 C11 模拟移动捕获的主要思路先把要移动的对象移动构造到std::bind生成的绑定对象里bind 会对右值参数做移动构造再让 lambda 以引用的方式使用 bind 对象里存储的这个移动后的对象bind 对象的生命周期和闭包绑定完全不用担心悬空问题。比如移动vector进闭包的写法std::vectordouble data; // 填充data... auto func std::bind( [](const std::vectordouble data) { /* 使用闭包内的data */ }, std::move(data) // 先移动到bind对象中 );总结C14 环境下直接用初始化捕获把对象移动到闭包中简洁又安全C11 没有初始化捕获就通过手写仿函数类或者std::bind的方式模拟实现移动捕获的效果。原著在线阅读地址