簡體   English   中英

將std :: unique_ptr返回給多態類對象的正確方法

[英]The correct way of returning std::unique_ptr to an object of polymorphic class

假設我有以下類的層次結構:

struct Base 
{
};

struct Derived : public Base 
{ 
    void DoStuffSpecificToDerivedClass() 
    {
    } 
};

以下工廠方法:

std::unique_ptr<Base> factoryMethod()
{
    auto derived = std::make_unique<Derived>();
    derived->DoStuffSpecificToDerivedClass();
    return derived; // does not compile
}

問題是, return語句沒有編譯,因為std::unique_ptr沒有具有協方差支持的復制構造函數(這是有意義的,因為它沒有任何復制構造函數),它只有一個具有協方差支持的移動構造函數。

解決這個問題的最佳方法是什么? 我可以想到兩種方式:

return std::move(derived); // this compiles
return std::unique_ptr<Base>(derived.release()); // and this compiles too

編輯1:我使用Visual C ++ 2013作為我的編譯器。 return derived的原始錯誤消息如下所示:

Error   1   error C2664: 'std::unique_ptr<Base,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : cannot convert argument 1 from 'std::unique_ptr<Derived,std::default_delete<Derived>>' to 'std::unique_ptr<Derived,std::default_delete<Derived>> &&'

編輯2:它是標准VS 2013模板中新創建的控制台應用程序。 我沒有調整任何編譯器設置。 編譯器命令行如下所示:

調試:

/Yu"stdafx.h" /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd"Debug\vc120.pdb" /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\CppApplication1.pch" 

發布:

/Yu"stdafx.h" /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc120.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\CppApplication1.pch" 

你可以這樣做:

return std::move(derived);

這樣你告訴編譯器不需要復制,這滿足了unique_ptr的要求。 如果類型匹配完美,則不需要明確指定move ,但在這種情況下,您可以。

正如問題中所述,問題是,return語句沒有編譯, std::unique_ptr沒有帶協方差支持的復制構造函數,它只有一個帶協方差支持的移動構造函數,但編譯器仍然沒有從std::unique_ptr<Derived>

這是因為從函數返回的對象移動的條件與復制省略的標准緊密相關,這嚴格要求返回的對象的類型需要與函數的返回類型相同。

[class.copy] / 32:

當滿足或將滿足復制操作的省略標准時,除了源對象是函數參數這一事實,並且要復制的對象由左值指定,重載決策選擇復制的構造函數是首先執行,好像對象是由右值指定的。

因此,我更喜歡,

return std::move(derived);

但是, DR-9R5中存在規則更改,因此即使類型不同,返回值也將被視為右值,gcc-5實現了規則,您無需更改gcc-5的代碼如圖所示這里

暫無
暫無

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

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