如何在std :: function中捕获unique_ptr

时间:2019-07-08 17:51:29

标签: c++ c++14

我需要将unique_ptr移至std::function闭包。我在C ++ 14中使用generalized lambda captures

auto ptr = make_unique<Foo>();

// Works.
auto lambda = [p = move(ptr)] { };

// This does not compile.
std::function<void()> func = [p = move(ptr)] { };

它正在尝试将Lambda捕获内容复制而不是移动到std::function中。相关错误是:

 copy constructor of '' is implicitly deleted because field '' has a deleted copy
      constructor
  std::function<void()> func = [p = move(ptr)] { };

示例here将使此方法似乎可行。

请注意,answer here仅重复了isocpp.org上的示例。

我可以按照以下步骤移至shared_ptr

shared_ptr<Foo> s = move(ptr);

但这带来了另一个问题,因为我需要在lambda中调用一个期望unique_ptr的函数,并且无法将shared_ptr转换回unique_ptr

是否可以在unique_ptr中捕获std::function

2 个答案:

答案 0 :(得分:1)

解决方案非常简单。与其将unique_ptr移到shared_ptr上,不如使用shared_ptr指向unique_ptr

auto holder = make_shared<unique_ptr<Foo>>(move(ptr));
std::function<void()> func = [holder] { MyFunction(move(*holder)); };

注意:在我的用例中,func仅被调用一次,所以move(*holder)可以。

答案 1 :(得分:0)

std :: function对象都可以复制

std::function是一种类型擦除对象,它支持复制存储的对象。

std::unique_ptr存储在lambda中时,该lambda不支持被复制。

因此std::function非常正确。它是一种可以复制的类型,当传入某些内容时,就可以确定如何复制它。 “我无法复制”不是有效答案;所有std::function都可以复制。

工业强度解决方案:

有两种常见方法可以解决此问题。首先,将std::function的状态存储在某种std::shared_ptr中。其次,您编写或找到一个非复制std::function,然后改用它。

更多的“现代” std::function替换库支持许多有用的东西:

  1. 功能视图,不拥有它们的包装。
  2. 不支持复制的仅移动功能​​对象。
  3. 多个重载函数对象,一次支持多个签名。
  4. 固定大小的缓冲区,如果没有足够的自动存储来代替堆分配,则无法编译。
  5. 简单可复制的功能对象

出于各种特殊目的,我个人需要以上每一项。

然后,当您不需要复制可调用对象并编译代码时,将使用moveonly_function<void()>

但是,这可能对于您现在的需求来说太重了。

一个快速的解决方案是:

template<class F>
auto make_shared_function( F&& f ) {
  return
   [pf = std::make_shared<std::decay_t<F>>(std::forward<F>(f))]
   (auto&&...args)->decltype(auto)
   {
     return (*pf)( decltype(args)(args)... );
   };
}

现在无论何时遇到此问题:

// This does not compile.
std::function<void()> func = make_shared_function([p = move(ptr)] { });

并且可调用对象的状态现在存储在共享的ptr中。