2015-11-08 83 views
2

假設我有下面的代碼,這是我的問題的一個簡單的例子:是否安全返回的成員變量是一個shared_ptr

#include <string> 
#include <iostream> 
#include <memory> 


class A{ 
    public: 
    std::string name() { return "class A"; } 
}; 

class B{ 
    public: 
    B(){ 
    m_a = std::make_shared<A>(); 
    } 

    std::shared_ptr<A> get_a() { return m_a; } 

    private: 
    std::shared_ptr<A> m_a; 
}; 

std::shared_ptr<A> foo() 
{ 
    B b; 
    return b.get_a(); 
} 

int main() 
{ 
    auto a = foo(); 
    auto name = a->name(); 
    std::cout << name; 
    return 1; 
} 

我想知道是安全的這樣做呢?作爲B實例的「b」將在函數foo結束時被釋放。主函數中的「a」是B :: m_a的shared_ptr。 「b」發佈後使用「a」是否安全?

非常感謝提前!

+0

也許重複? https://stackoverflow.com/questions/10643563/how-to-return-smart-pointers-shared-ptr-by-reference-or-by-value和https://stackoverflow.com/questions/974964/best-練習何時返回智能指針? – coincoin

+0

請發佈可編輯代碼。即沒有語法錯誤,帶有正確的'main'和'#include's。 –

+0

我已經閱讀了兩個問題,但是我決定發佈一個新問題,因爲我想確保這樣做是安全的(或不安全),將「shared_ptr」作爲成員變量的「父」類超出範圍。 – Song

回答

1

是的,它很安全。如果這不安全,那麼std::shared_ptr將是無用的。

作爲B的實例的「b」將在函數foo的末尾被釋放。

是的,但它的std::shared_ptr<A>之前被複制。

讓我們看看都有哪些功能的最後一行確實:

return b.get_a(); 

get_a()產生std::shared_ptr<A>,它被複制到一個臨時對象。然後再次複製此臨時對象std::shared_ptr<A>以成爲main中調用的結果。

(實際拷貝甚至可能被省略,由於返回值優化,但是這不會改變任何東西。如果有的話,它使安全性更容易理解。)

只有然後b摧毀,但在它的std::shared_ptr<A>已經到那個時候複製。

bstd::shared_ptr<A>實例被銷燬,也不過爲A對象的內存是釋放。 這就是std::shared_ptr的整點 - 它知道它被複制的頻率以及只有當最後一個副本被銷燬時才釋放動態分配的內存。

主函數中的「a」是B :: m_a的shared_ptr。

不,這是一個std::shared_ptr<A>,但就是這樣。它與原來的B::m_a無關。

「b」發佈後使用「a」是否安全?

是的,因爲ab之間沒有持久關係。


基本上,您質疑安全是C++的一個基本特性,即從函數返回值。與返回std::stringint相比,返回std::shared_ptr與安全性沒有區別。當從函數返回值時,總是會發生什麼情況:要返回的值被複制,原始數據被銷燬,副本繼續存在。

5

foo也就是說

shared_ptr<A> foo() 
{ 
    B b; 
    return b.get_a(); 
} 

不會在構件的把一索引返還A B構件,而是一個複製standonly(的拷貝,如果沒有最優化RV);和shared_ptr a

auto a = foo(); 

將A堆實例從銷燬保存到作用域結束。

因此,我認爲這是安全的,儘管創作者們畢竟只是他們創建和發佈的許多共享資產的一個用戶。

換句話說 - 最後一個關燈,而不是打開燈。

live at Coliru

0

它是安全的。

shared_ptr在堆上創建一個跟蹤變量。這使得對象B更加複雜,因爲即使它在堆棧上創建,它也會從堆中分配A。可能影響性能。

當跟蹤數據的所有用戶都停止訪問它時,shared_ptr<>被刪除。

相關問題