【问题标题】:Get a reference to the lambda's captured value获取对 lambda 捕获值的引用
【发布时间】:2017-01-09 11:58:09
【问题描述】:

我正在使用一个签名类似于此的函数(不是我的,来自我无法控制的库):

template<typename T, typename F>
void do_async(T const&, F); // the second parameter is a callable

它通常是这样使用的

do_async(obj, [this](){ ... });

我写了一个与此类似的函数,它总是使用相同的回调 lambda:

template<typename T>
void do_async_wrapper(T obj) {
    do_async(obj, [this](){ ... });
}

我的问题源于这样一个事实,因为 obj 是作为引用传递的,所以它必须保持活动状态,直到调用回调。我的函数应该处理这个问题,所以调用者不必担心对象的生命周期。这就是它按价值接受的原因。
为了让它保持活力,我想做这样的事情:

template<typename T>
void do_async_wrapper(T obj) {
    do_async(obj, [this, obj{std::move(obj)}](){ ... });
}

显然,这不会(总是)按原样工作,因为引用指向不再存在的函数本地引用,而保持活动状态的引用是它的(移动)副本。

有什么建议吗?

【问题讨论】:

  • do_async 使用该参数做什么?你确定它不会在内部复制吗?
  • @TartanLlama 是的。库文档指定调用者有责任确保对象保持活动状态。
  • 你能链接到文档吗?一种选择是std::shared_ptr
  • @TartanLlama 这将涉及在堆上分配另一个对象,除了 lambda 对象(我开始认为这可能是不可避免的)
  • 如果异步启动器和异步任务都需要访问缓冲区,这对于std::shared_ptr 来说是一个相当不错的用例,即使是动态分配。

标签: c++ c++11 lambda c++14


【解决方案1】:

由于函子是按值获取的,因此您不能将对象直接存储在函子中并传递对它的引用。 您可以通过使用智能指针作为shared_ptr 来解决这个问题:

template<typename T>
void do_async_wrapper(T obj) {
    auto ptr = std::make_shared<T>(std::move(obj));
    do_async(*ptr, [this, ptr](){ /*...*/ });
}

【讨论】:

  • 我会被make_unique 而不是make_shared 所吸引,因为do_async 不应该复制 lambda。但这需要额外的一行来使其以定义的方式工作 (auto&amp; obj_ref = *ptr;)。
  • @Yakk 我使用 make_unique 采用了类似的解决方案。我不需要你显示的那条线。它的意义何在?
  • @baruch:有2个问题,*ptr[ptr = std::move(ptr)]之间的未指定顺序,以及do_asyncF的副本(这使得T的2个实例不同)。
猜你喜欢
  • 1970-01-01
  • 2019-08-28
  • 2018-01-17
  • 2016-02-08
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多