2012-08-28 88 views
4

考慮我有一個容器std::map<int, std::shared_ptr<MyClass>>,我想填充它的外部功能,並避免處理其內容。所以我有如何正確處理移動構造函數的shared_ptr映射?

typedef Container std::map<int, std::shared_ptr<MyClass>> 

Container&& f(){ 
    Container bar; 
    auto foo = std::shared_ptr<MyClass>(new MyClass()); 
    bar.insert(std::make_pair(0,foo)); 
    std::cout<<bar.at(1)->print_smth<<'\n'; //This works 
    return std::move(bar); 
} 

int main(){ 
    Container baz(f()); 
    std::cout<<bar.at(1)->print_smth<<'\n'; //This doesn't 
    // Container baz has element 1, but shared_ptr is invalidated, because it has 0 references. 

} 

如果我使用傳統的複製構造函數,一切都按預期工作。

+0

返回值已經是一個右值,並且極有可能沒有因RVO而做的副本。 – Cubic

+5

您不得返回對本地自動對象的引用。訪問該引用的行爲是未定義的。 –

+0

@Cubic在實踐中使用現代編譯器優化啓用你是正確的,但我stiil不明白我做錯了什麼。 – galadog

回答

6

這是太複雜了。爲什麼不這樣說:

int main() 
{ 
    Container baz { { 0, std::make_shared<MyClass>() } }; 

    // ... 
} 

如果你絕對必須的輔助函數去,你必須返回一個對象,而不是懸空的參考。事情是這樣的:

Container f() 
{ 
    return Container { { 0, std::make_shared<MyClass>() } }; 
} 

很難沉溺於什麼比這更行人,但最後一個,永不要被使用在家裏版本:

Container f() 
{ 
    Container bar; 
    auto p = std::make_shared<MyClass>; 

    bar[0] = p;      // Method #1 
    // ---- ALTERNATIVELY --- 
    bar.insert(std::make_pair(0, p)); // Method #2 
    // ---- ALTERNATIVELY --- 
    bar.emplace(0, p);     // Method #3 

    return bar; 
} 
+0

當然我在發佈之前簡化了我的代碼。助手功能要大得多。但是,我的代碼第二個和第三個例子有什麼不同? – galadog

+0

@galadog:1)返回類型,2)返回語句,3)創建共享指針。 –

+0

@galadog:您的代碼通過引用返回,此代碼按值返回。這意味着你的代碼在被銷燬之後(並且因此具有UB)最終使用對象,而代碼不會。 – Mankarse

0

的問題是,你正在從您的f()返回參考。一個右值引用仍然是一個引用,就像你永遠不會從一個函數中返回一個本地引用一樣,你也不能用右值引用來實現。

好消息是,你不必。感謝return value optimization,你可以簡單地從f()返回一個Container,它會做你正在尋找的。

+0

你確定你的意思是「左值」? :-( –

+0

對不起,我的意思是右值 – Fozi