《Effective Modern C++》学习笔记之条款三十二:使用初始化捕获将对象移入闭包

如果你有一个对象,其复制操作开销昂贵,而移动操作成本低廉,而你又需要把该对象放入闭包,那么你肯定更愿意移动该对象,而非复制它。

C++14为我们提供了一个全新的捕获方式---初始化捕获,也叫做广义lambda捕获,使用初始化捕获,则你会得到机会指定:

  1. 由lambda生成的闭包类中的成员变量名字。

  2. 一个表达式,用以初始化该成员变量。

例如使用初始化捕获将std::unqiue_ptr移动到闭包内:

class Widget {                  //一些有用的型别
public:
    ...

    bool isValidted() const;
    bool isProcessed() const;
    bool isArchived() const;
private:
    ...
};
auto pw = std::make_unique<Widget>();   //创建Widget
                                        //关于std::make_unique,参见Item 21

...                                     //配置*pw

auto func = [pw = std::move(pw)]            //采用std::move(pw)
            { return pw->isValidated() &&   //初始化闭包类的数据成员
                    pw->isArchived();};

[] 中的那段代码就是初始化捕获,位于“=”左边的,是你所指定的闭包类成员变量的名字,而位于其右侧是初始化表达式,且它们处于不同的作用域,左侧作用域就是闭包类的作用域,右侧的作用域与lambda式加以定义之处的作用域相同。

pw=std::move(pw)表达了"在闭包中创建一个成员变量pw,然后使用针对局部变量pw实施std::move的结果来初始化该成员变量"

C++11显然并不支持这种初始化捕获,那该如何在C++11中实现移动捕获呢?

在C++11中按移动捕获可以采用以下方法模拟,只需要:

  1. 把需要捕获的对象移动到std::bind产生的函数对象中。
  2. 给到lambda式一个指涉到欲“捕获”的对象的引用。

例如,如果你想创建一个局部的std::vector对象,向其放入一组值,然后将其移动入闭包。在C++14使用初始化捕获,非常简单:

std::vector<double> data;       //欲移入闭包的对象

...                             //灌入数据

auto func = [data = std::move(data)]    //C++14的初始化捕获
            {/* 对数据加以运用 */}

但是在C++11中,你必须借助std::bind生成函数对象:

std::vector<double> data;       //同前

...                             //同前

auto func = std::bind(
            [](const std::vector<double>& data)    //C++11中模拟移动捕获的部分
            {/* 对数据加以运用 */},
            std::move(data)
        );

和lambda表达式类似地,std::bind也生成函数对象,第一个实参是个可调用对象,第二个实参表示传给该对象的值。

我们知道,std::bind对于每个左值实参,在绑定对象内的对应的对象内对其实施的是复制构造,而对每个右值实参,实施的则是移动构造。所以当一个绑定对象被“调用”,也就是当func(绑定对象)被调用时,func内经由移动构造出所得到的data的副本就会作为实参传递给那个原先传递给std::bind的lambda式。

至此,我们应该知道以下知识点:

  1. 移动构造一个对象入C++闭包是不可能实现的,但移动构造一个对象入绑定对象则是可以实现的
  2. 欲在C++11中模拟移动捕获,需要包含以下步骤:
    1. 先移动构造一个对象入绑定对象
    2. 然后按照引用把移动构造所得的对象传递给lambda表达式
  3. 因为绑定对象的生命周期和闭包相同,所以针对绑定对象中的对象和闭包内的对象可以采用相同手法处置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiang木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值