簡體   English   中英

如何在 std::function 中捕獲 unique_ptr

[英]How to capture a unique_ptr in a std::function

我需要將unique_ptr移動到std::function閉包。 我在 C++14 中使用廣義 lambda 捕獲

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)] { };

此處的示例將使這看起來有效。

請注意, 這里答案只是重復了 isocpp.org 上的示例。

我可以移動到shared_ptr如下:

shared_ptr<Foo> s = move(ptr);

但這會產生另一個問題,因為我需要從我的 lambda 中調用一個需要unique_ptr的函數,而且我無法將shared_ptr轉換回unique_ptr

是否可以在std::function捕獲unique_ptr

std::function 對象都可以復制

std::function是一個類型擦除對象,支持復制存儲的對象。

當您在 lambda 中存儲std::unique_ptr時,該 lambda 不支持被復制。

所以std::function非常正確地抱怨。 它是一種可以復制的類型,當傳入某些東西時,它會計算出如何復制它。 “我不能復制它”不是一個有效的答案; 所有std::function都可以復制。

工業強度解決方案:

有兩種常見的方法可以解決這個問題。 首先,您將std::function的狀態存儲在某種std::shared_ptr中。 其次,您編寫或找到一個非復制的std::function並使用它。

更多“現代” std::function替換庫支持許多有用的東西:

  1. 函數視圖,不擁有它們所包裝的內容。
  2. 僅移動函數對象,不支持復制。
  3. 多重重載函數對象,一次支持 1 個以上的簽名。
  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 中。

解決方案非常簡單。 不是將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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM