C 11智慧型指標之std shared ptr

2021-08-02 02:07:44 字數 3848 閱讀 9789



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...