[英]Returning local unique_ptr as a shared_ptr
我習慣於在返回std::unique_ptr
時不使用std::move
,因為這樣做會禁止RVO。 我有這種情況,我有一個本地std::unique_ptr
,但返回類型是一個std::shared_ptr
。 以下是代碼示例:
shared_ptr<int> getInt1() {
auto i = make_unique<int>();
*i = 1;
return i;
}
shared_ptr<int> getInt2() {
return make_unique<int>(2);
}
unique_ptr<int> getInt3() {
auto ptr = make_unique<int>(2);
return ptr;
}
int main() {
cout << *getInt1() << endl << *getInt2() << *getInt3() << endl;
return 0;
}
GCC接受這兩種情況,但Clang拒絕getInt1()
此錯誤:
main.cpp:10:13: error: no viable conversion from 'std::unique_ptr<int, std::default_delete<int> >' to 'shared_ptr<int>'
return i;
^
兩個編譯器都接受第三種情況。
哪一個錯了? 謝謝。
正確答案取決於您所談論的C ++標准。
如果我們談論的是C ++ 11,那么clang是正確的(需要明確的移動)。 如果我們談論C ++ 14,gcc是正確的(不需要顯式移動)。
C ++ 11在N3290 / [class.copy] / p32中說:
當滿足或將滿足復制操作的省略標准時,除了源對象是函數參數這一事實,並且要復制的對象由左值指定,重載決策選擇復制的構造函數是首先執行,好像對象是由右值指定的。 如果重載解析失敗,......
這要求您只在返回表達式與函數返回類型具有相同類型時才獲得隱式移動。
但CWG 1579對此進行了更改,並且此缺陷報告在C ++ 11之后被接受,並且及時用於C ++ 14。 這一段現在寫着:
當滿足復制/移動操作的省略標准時,但不滿足異常聲明 ,並且要復制的對象由左值指定,或者當
return
語句中的表達式是(可能帶有括號的) id-時表達式 ,用於在最內層封閉函數或lambda-expression的body或parameter-declaration-clause中聲明的具有自動存儲持續時間的對象,首先執行重載決策以選擇復制的構造函數,就像對象由rvalue指定一樣。 如果第一個重載決議失敗或未執行,...
此修改基本上允許返回表達式類型可轉換為函數返回類型,並且仍然有資格進行隱式移動。
這是否意味着代碼需要基於__cplusplus
的值的#if
/ #else
?
人們可以做到這一點,但我不會打擾。 如果我的目標是C ++ 14,我會:
return i;
如果代碼在C ++ 11編譯器下意外運行,則會在編譯時通知您錯誤,並且修復它是很容易的:
return std::move(i);
如果您只是針對C ++ 11,請使用move
。
如果要同時定位C ++ 11和C ++ 14(及更高版本),請使用move
。 無償使用move
的缺點是你可以抑制RVO(返回值優化)。 但是,在這種情況下,RVO甚至不合法(因為從return
語句轉換為函數的返回類型)。 所以無償的move
不會傷害任何事情。
即使在針對C ++ 14時你有可能傾向於無償的move
,如果沒有它,事情仍然在C ++ 11中編譯,並且調用昂貴的復制轉換,而不是移動轉換。 在這種情況下,在C ++ 11下意外編譯會引入靜默性能錯誤。 當在C ++ 14下編譯時,無償的move
仍然沒有任何不利影響。
std::unique_ptr
只有在它是rvalue時才能用於構造std::shared_ptr
。 請參閱std::shared_ptr
的構造函數聲明:
template< class Y, class Deleter >
shared_ptr( std::unique_ptr<Y,Deleter>&& r );
所以你需要使用std::move
來使第一個案例工作,否則它應該失敗。
return std::move(i);
順便說一句:我用gcc 4.9.3編譯代碼也失敗了。
source_file.cpp:14:12: error: cannot bind ‘std::unique_ptr<int, std::default_delete<int> >’
lvalue to ‘std::unique_ptr<int, std::default_delete<int> >&&’
return i;
^
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.