std::shared_ptr
是在c++11
中引入的一種智慧型指標,其特點是它所指向的資源具有共享性,即多個
shared_ptr
可以指向同乙份資源。在
c++中使用
shared_ptr
需要包含
標頭檔案。
一、定義並初始化乙個共享指標的三種方式
:class
investment
virtual
~investment() };
1通過new
運算子或者普通指標
shared_ptr
<
investment
> sp(
newinvestment
());
investment * pinvestment =new investment();
shared_ptrsp(pinvestment); 2
通過make_shared方法
auto
sp1 = std::make_shared<
investment
>(); 3
通過拷貝另乙個智慧型指標
shared_ptr
<
investment
> sp2(sp); 或者
shared_ptr
<
investment
> sp3 = sp2;
相比於普通指標,共享指標要占用多一倍的記憶體空間,其內部包含兩個指標,乙個指標指向它所管理的資源,第二個指標指向乙個稱為「
control block
」的控制塊,如圖所示:
通過上圖所示的結構,我們可以知道在控制塊中有乙個引用計數字段(
reference count
),用來記錄指向
object
的共享指標數量,當我們宣告並初始化乙個共享指標時,
reference count
的值為1
,當有另乙個共享指標指向該
object
時(比如通過賦值或拷貝建構函式,將乙個共享指標賦值給另一共享指標),
reference count
的值遞增1。
第二個字段:
weak count
,也是乙個引用計數,它用來計數指向該
object
的std::weak_ptr
指標的數量,關於
std::weak_ptr
我們將在下一章節討論。
引用計數的存在使得
std::shared_ptr
有一些比較特別的特性:
std::shared_ptr
的大小兩倍於普通指標。
控制塊必須是動態分配的,這是由於被
shared_ptr
所管理的物件並不知道有「引用計數」的存在,所以在被管理物件中並沒有空間來儲存這個引用計數。
引用計數的增減必須是原子性的,否則在多執行緒環境下,由於執行緒競爭的存在,會導致對
reference count
的髒讀、髒寫。
shared_ptr
預設情況下使用
delete
釋放資源,但是使用者也可以指定自己的資源釋放函式,例如在下面這個例子中,
pinvest
用delete_investment
進行資源釋放操作:
auto
delete_investment = (
investment
*pinv)
; shared_ptrpinvest(new investment(),delete_investment)
資源釋放器的位址存放於控制塊(
control block
)中,因此增加使用者自定義的資源釋放器不會增加
shared_ptr
的大小,其大小仍然為兩個指標的大小。
當**第一次為乙個物件建立
shared_ptr
指標指向這個物件的時候,控制塊就會被建立,或者說它應該被建立。但是問題在於,一處**在建立
shared_ptr
來指向乙個物件時,這處**並不知道它建立的這個
shared_ptr
所要指向的物件是否已經有別的
shared_ptr
指向了,即這個物件是否已經有乙個控制塊與之對應了。為了解決這個問題,控制塊的建立遵循以下原則:
std::make_shared
總是會建立乙個控制塊。這是因為當呼叫
std::make_shared
建立智慧型指標的時候,智慧型指標所要指向的這個物件是第一次被建立的。
當通過乙個普通指標作為引數構建乙個智慧型指標的時候,會為這個指標所指向的物件建立乙個控制塊。
在這種情況下,如果使用者想要為乙個已經有控制塊的物件建立乙個
shared_ptr
時,需要用
shared_ptr
或者weak_ptr
作為共享指標建構函式的引數,而不能用普通指標作為引數。
注意:使用普通指標作為引數構造乙個
shared_ptr
有可能會導致多個控制塊(
control block
)的建立。這種情形並不總是會很容易的被意識到,看下面的例子:
假設投資類中有乙個函式來處理投資,乙個
vector
來追蹤被處理過的投資,**如下:
std::
vector
<
shared_ptr
<
investment
>> m_ptrvec;
class
investment ;
void
investment
::handler()
在投資處理函式
handler
中,用this
作為引數傳給
vector
的emplace_back
函式,但這樣做其實蘊藏了風險,試想如果在**中的其他地方有乙個
shared_ptr
也指向了這個投資物件,這樣就會有兩個控制塊被建立起來。那麼,有沒有一種辦法,讓我們可以使用
this
指標構造
shared_ptr
,但是又不會引起控制塊的重複建立呢?
幸運的是,在
stl中有乙個模板類正是為此而生,它就是
std::enable_shared_from_this
。**要達到這個目的,必須繼承
std::enable_shared_from_this
類,並將
this
指標用shared_from_this()
介面代替,就像下面的**一樣:
class
investment
:public
std::
enable_shared_from_this
<
investment
> ;
void
investment
::handler()
shared_from_this()
會查詢當前物件的控制塊,並建立乙個新的
shared_ptr
關聯到這個控制塊。如果這個物件還沒有與之對應的控制塊,
shared_from_this()
會丟擲異常。 沒有
std::shared_ptr.
所以shared_ptr
只能管理單個物件,而不能管理物件陣列。
C 11之智慧型指標
c 98提供了了智慧型指標auto ptr,但c 11已將其摒棄,並提供了unique ptr和shared ptr。這三種智慧型指標模板都定義了類似指標的物件,可以將new獲得的位址賦給這種物件。當智慧型指標過期時,這些記憶體將自動被釋放。其基本用法如下 include include inclu...
c 11之智慧型指標
由於在c 中我們可以動態分配記憶體,但有時候我們會忘記用 delete或free釋放記憶體,就會導致記憶體洩露。所以c 11提供了智慧型指標這種東西 本文參考了知乎某知乎友的 比如下面這兩種情況 1 記憶體洩漏 str1所指的資源沒有被釋放 2 多重釋放,引起程式崩潰 可能平時都寫在乙個檔案不會忘記...
C 11智慧型指標
本文介紹c 的四種智慧型指標,其中後三種是c 11新增加的,auto ptr已被棄用。要編譯c 11,需要安裝g 4.8 sudo add apt repository ppa ubuntu toolchain r test sudo apt get update sudo apt get inst...