条款32:使用初始化捕获将对象移入闭包
在 C++11 中,lambda 的捕获列表 [] 只能捕获在 lambda 所在作用域内可见的变量,捕获方式只有两种:按值复制或按引用。这导致了一个问题:C++11 无法直接将对象“移动”到闭包中。
这个局限对两类对象影响很大:
只移类型 (Move-only Types):像 std::unique_ptr、std::future 或 std::thread 这样的类型,它们是不能被复制的。因此,在 C++11 中,你无法将它们捕获到 lambda 闭包中。
复制成本高昂的类型:像 std::vector 或 std::string 这样的大多数标准库容器,复制它们的成本可能很高,但移动它们的成本却很低。在 C++11 中,如果你想在闭包中拥有一份容器的副本,你只能付出高昂的复制代价。
这个问题就是下面介绍的初始化捕获所要解决的
C++14 解决方案:初始化捕获 (Init Capture)
C++14 引入了一种全新的、更强大的捕获机制,被称为初始化捕获,也叫广义 lambda 捕获 (generalized lambda capture)。它彻底解决了 C++11 的局限。
初始化捕获允许你做两件事:在 lambda 生成的闭包类中,指定一个新成员变量的名字; 提供一个表达式,用于初始化该成员变量。
语法为:[新变量名 = 初始化表达式]
下面是利用初始化捕获实现移动捕获的一个例子:
1 | auto pw = std::make_unique<Widget>(); |
此外, 初始化捕获甚至能“捕获”一个表达式的结果,这是 C++11 捕获完全做不到的:
1 | // C++14: 直接用表达式的结果初始化闭包成员 |