首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++核心准则F.52:在lambda表达式中使用引用形式捕捉局部变量

C++核心准则F.52:在lambda表达式中使用引用形式捕捉局部变量

作者头像
面向对象思考
发布2020-03-25 15:40:10
1.3K0
发布2020-03-25 15:40:10
举报

F.52: Prefer capturing by reference in lambdas that will be used locally, including passed to algorithms

F.52 在lambda表达式中使用引用形式捕捉局部变量,包含向算法传递变量的情况。

译者注:如果你不清楚捕捉(capture)是什么,请参考

https://mp.weixin.qq.com/s/VuW_5OcX7uUUrMbsN2wxPQ

Reason(原因)

For efficiency and correctness, you nearly always want to capture by reference when using the lambda locally. This includes when writing or calling parallel algorithms that are local because they join before returning.

为了效率和正确性,在本地使用lambda表达式时,你差不多总是需要通过引用方式捕捉变量。这包括编写或者调用本地并发算法的情况,因为它们需要在返回前汇合(从而保证安全性,译者注)。

Discussion(讨论)

The efficiency consideration is that most types are cheaper to pass by reference than by value.

关于效率的考虑:对于大多数类型来说,传引用都会比传值的成本更低。

The correctness consideration is that many calls want to perform side effects on the original object at the call site (see example below). Passing by value prevents this.

关于正确性的考虑:许多调用都希望(在被调用函数被执行的同时,)对处于调用侧的原始对象产生连带效果(参考下面的示例)。传值做不到这一点。

Note(注意)

Unfortunately, there is no simple way to capture by reference to const to get the efficiency for a local call but also prevent side effects.

不幸的是,对于局部调用,不存在简单的方法可以通过引用捕捉常量类型变量获得效率又可以避免连带效果。

译者注:常量类型应用应该指的是在函数声明中的被声明为常量的引用参数,通过这种方式可以同时提供高效率和写保护。

Example(示例)

Here, a large object (a network message) is passed to an iterative algorithm, and is it not efficient or correct to copy the message (which may not be copyable):

这里,一个大对象(一个网络消息)传递给一个迭代算法,拷贝该消息不是高效或者正确的做法(它也许不能拷贝):

std::for_each(begin(sockets), end(sockets), [&message](auto& socket)
{
    socket.send(message);
});

译者注:每次循环都拷贝的代价也很高。

Example(示例)

This is a simple three-stage parallel pipeline. Each stage object encapsulates a worker thread and a queue, has a process function to enqueue work, and in its destructor automatically blocks waiting for the queue to empty before ending the thread.

这是一个简单的三阶段并发管道。每个state对象封装一个工作线程和一个队列,有一个process函数处理入队,它的析构函数在关闭线程之前自动地进入阻塞状态以等待队列变空。

void send_packets(buffers& bufs)
{
    stage encryptor([] (buffer& b){ encrypt(b); });
    stage compressor([&](buffer& b){ compress(b); encryptor.process(b); });
    stage decorator([&](buffer& b){ decorate(b); compressor.process(b); });
    for (auto& b : bufs) { decorator.process(b); }
}  // automatically blocks waiting for pipeline to finish

译者注:代码中使用的是隐式捕捉,具体可以参考:https://mp.weixin.qq.com/s/RNpLqwekN3BJUbIN-DwVxQ

Enforcement(实施建议)

Flag a lambda that captures by reference, but is used other than locally within the function scope or passed to a function by reference. (Note: This rule is an approximation, but does flag passing by pointer as those are more likely to be stored by the callee, writing to a heap location accessed via a parameter, returning the lambda, etc. The Lifetime rules will also provide general rules that flag escaping pointers and references including via lambdas.)

标记lambda表达式采用引用方式捕获变量,但是没有在函数范围内本地使用,或者通过引用方式传递给另外一个函数的情况。

注意:这是一个近似的规则,但是确实可以标记出:通过很有可能被调用者保存的指针进行的传递,对通过参数访问的堆上的某处进行的写入,返回lambda表达式等等。生命周期准则群组也会提供标记逃逸指针和参照的普遍准则,也会包含源自lambda表达式的情况。

觉得本文有帮助?请分享给更多人

关注【面向对象思考】,每天前进一小步

有任何疑问,欢迎留言提问或讨论


面向对象设计,面向对象编程,面向对象思考!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 面向对象思考 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • F.52: Prefer capturing by reference in lambdas that will be used locally, including passed to algorithms
  • https://mp.weixin.qq.com/s/VuW_5OcX7uUUrMbsN2wxPQ
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档