簡體   English   中英

如果 std::function 捕獲了 unique_ptr,如何復制它?

[英]How can std::function be copied if it captures a unique_ptr?

#include <iostream>
#include <memory>
#include <functional>

struct PacketFrom
{
    typedef std::unique_ptr<PacketFrom> SPtr;
};

template<class P> 
class R{
    public:
    void queue_read(P *t)
    {
        doSomething([t = typename PacketFrom::SPtr(t)](){test(std::move(t));});
    }

    void doSomething(std::function<void()> f) {

    }

    void test(PacketFrom::SPtr p) {

    }
};

int main()
{
    R<PacketFrom> r;

    return 0;
}

如果 lambda 函數是通過副本傳遞的,那么這段代碼如何工作? lambda 擁有一個無法復制的unique_ptr 我認為它根本沒有捕獲 unique_ptr 所以我添加了test()只是為了確保它正在捕獲。 但是代碼編譯得很好。

從這個意義上說,這段代碼實際上並不“工作”。 它可以編譯,但只是因為您從未調用queue_read

如果您嘗試使用它(這會強制編譯器實際實例化R<P>::queue_read ,直到那時它才必須這樣做),那么每個編譯器都會出現錯誤:

template<class P> 
class R{
    public:
    void queue_read(P *t)
    {
        doSomething([this, t = std::unique_ptr<P>(t)]() { test(std::move(t)); });
    }

    void doSomething(std::function<void()> f) {
        (void)f;
    }

    void test(std::unique_ptr<P> p) {
        (void)p;
    }
};

int main()
{
    R<int> r;
    r.queue_read(new int(1));

    return 0;
}

叮當 9.0:

 error: call to deleted constructor of 'std::unique_ptr<int>' doSomething([this, t = std::unique_ptr<P>(t)]() { test(std::move(t)); });

海灣合作委員會 9.2:

 error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]' 11 | doSomething([this, t = std::unique_ptr<P>(t)]() { test(std::move(t)); });

MSVC 19.22:

 error C2280: 'std::unique_ptr<P,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function

https://godbolt.org/z/KmjVJB (感謝理查德!)

同樣,這里的關鍵是編譯器實際上並沒有編譯queue_read的代碼,因為沒有必要。 由於在類體內定義,該函數是隱式inline的。 為某些P實例化R<P>只會導致聲明,而不是其成員函數的定義被實例化。 只有當你真正調用queue_read ,編譯器才會抱怨。

順便說一下,這是一件好事。 您可以使用std::vector<MoveOnlyType>並執行不需要復制的所有操作,即使某些std::vector成員函數需要可復制類型。 但只要你從不使用后面的功能,一切都很好。 如果編譯器總是實例化所有成員函數定義並報告其中的錯誤(即使從未使用過),那將會更加麻煩。

如果 std::function 捕獲了 unique_ptr,如何復制它?

std::function不捕獲任何內容。

捕獲不可復制對象(例如std::unique_ptr )的 lambda 本身是不可復制的。 這樣的 lambda 不滿足,也沒有任何其他不可復制的函數對象類型滿足std::function的要求,這要求函子是可復制的。 標准規則(來自最新草案):

[func.wrap.func.con]

 template<class F> function(F f);

要求: F 應為 Cpp17CopyConstructible。


但是代碼編譯得很好。

當格式錯誤的函數是模板的未使用函數時,這是典型的。 如果您嘗試調用該函數,它應該無法編譯。

暫無
暫無

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

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