簡體   English   中英

Lambda 在轉讓所有權時按價值捕獲

[英]Lambda capture-by-value while transfering ownership

我有一個管理所有權某些資源的 RAII 樣式 class。 因此,復制構造函數和賦值運算符被顯式刪除,僅存在移動變體,它們移動資源並使源(引用)無效。 So far it has worked fine, but now I would like to move an object of that kind into a std::function which is processed somewhere else, so that this object becomes the ownership carrier, and eventually release the object. 幸運的是,C++14 允許在按值捕獲時使用移動分配,因此它看起來像 go 的方式。 就像是:

std::function<void()> act = [temp = move(resCarrier), description]() mutable {
    try {
// hopefully exception-safe
        auto c = make_unique<DataProcessor>(move(temp), description);
        c->doStuff();
    }  catch (...) {}
};
scheduler->RunLater(move(act));

但沒那么容易。 它應該工作,但它沒有。 得到凌亂的模板錯誤,最終以這個結束(為了清楚起見略短)。

/usr/include/c++/10/bits/std_function.h:161:6: error: use of deleted function ‘<WHOLE SIGNATURE OF CURRENT FUNCTION>::<lambda()>&)’
...
note: ‘<WHOLE SIGNATURE OF CURRENT FUNCTION>::<lambda()>&)’ is implicitly deleted because the default definition would be ill-formed:
   99 |   std::function<void()> act = [temp = move(resCarrier), description]() mutable
      |                                                                    ^
...
error: use of deleted function ‘TResCarrier::TResCarrier(const TResCarrier&)’

所以看起來編譯器基本上忽略了移動語義,並堅持使用復制構造函數,同時捕獲 lambda 聲明中的變量。 到目前為止,我無法說服它以不同的方式處理它。 到目前為止,“最好”的想法是圍繞攜帶的 object 創建另一個級別的重定向,以便可以按值復制和捕獲它(例如資源周圍的 shared_ptr )。 但這將是沒有充分理由的運行時開銷。

我是否忽略了某些東西,或者在 std::function 或 lambda 到函數映射的限制后面是否存在隱藏的討厭的類型擦除限制?

A lambda 不是std::function

你是對的,c++14 允許將某些東西移動到 lambda 中,甚至在之后移動所說的 lambda。

另一方面, std::function要求可調用對象是可復制構造和可復制分配的。

來自cppreference

Class 模板 std::function 是一個通用的多態 function 包裝器。 std::function 的實例可以存儲、復制和調用任何 CopyConstructible Callable 目標——函數、lambda 表達式、綁定表達式或其他 ZC1C425268E68385D1AB5074C17A94F 對象以及指向成員函數的指針和指針41。

存儲的可調用 object 稱為 std::function 的目標。 如果 std::function 不包含目標,則稱為空。 調用空 std::function 的目標會導致拋出 std::bad_function_call 異常。

std::function 滿足 CopyConstructible 和 CopyAssignable 的要求。

可能的解決方案的一些想法可能是:

  • 創建您自己的 function 包裝器(或使用庫),它支持僅移動可調用對象。

  • std::unique_pre包裹在std::shared_ptr並捕獲它。

第一個選項似乎更強大,但只是為了展示快速解決問題的想法。

#include <memory>
#include <functional>

int main() {
    auto moveonly = std::make_unique<int>(5);
    auto wrapped = std::make_shared<std::unique_ptr<int>>(std::move(moveonly));

    auto lam = [wrapped]() {
        return *(*wrapped);
    };

    std::function<int()> f = lam;
}

暫無
暫無

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

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