[英]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.