C 之「智慧型指標」

2021-09-22 12:29:48 字數 4159 閱讀 9198

1. 引入

要確保用 new 動態分配的記憶體空間在程式的各條執行路徑都能被釋放是一件麻煩的事情。

c++11 模板庫的 標頭檔案中定義的智慧型指標,即 shared_ptr 模板,就是用來部分解決這個問題的。

只要將 new 運算子返回的指標 p 交給乙個 shared_ptr 物件「託管」,就不需要再單獨編寫delete p語句,

託管 p 的 shared_ptr 物件在消亡時會自動執行delete p。而且,該 shared_ptr 物件能像指標 p 一樣使用,

即假設託管 p 的 shared_ptr 物件叫作 ptr,那麼 *ptr 就是 p 指向的物件。

2. 使用說明

通過 shared_ptr 的建構函式,可以讓 shared_ptr 物件託管乙個 new 運算子返回的指標,寫法如下: 

shared_ptrptr(new t);  // t 可以是 int、char、類等各種型別

//此後,ptr 就可以像 t* 型別的指標一樣使用,即 *ptr 就是用 new 動態分配的那個物件。

//shared_ptr是一種計數指標,當shared_ptr所指物件的引用計數變為0時,該物件就會被自動刪除。

3. 注意

a. 多個 shared_ptr 物件可以共同託管乙個指標 p。

★★★當所有曾經託管 p 的 shared_ptr 物件都解除了對其的託管時,就會執行delete p。

b. 只有指向動態分配的物件的指標才能交給 shared_ptr 物件託管。

若將指向普通區域性變數、全域性變數的指標交給 shared_ptr 託管,編譯時不會有問題,但程式執行時會出錯。

因為不能析構乙個並沒有指向動態分配的記憶體空間的指標。

c. 因為智慧型指標是模擬指標的模板類,目的是自動**堆,故必須給智慧型指標傳遞「堆」,在給shared_ptr分配記憶體時使用make_shared函式更安全。

4. 例項

#include #include using namespace std;

class a

~a()

};int main()

程式的輸出結果如下:

2,2,223

2 destructed

end5 destructed

4 destructed

3 destructed

/**解析**/

⑴ 讓多個 shareclptr 物件託管同乙個指標時,這多個 shared_ptr 物件會共享乙個對共同託管的指標的「託管計數」。  【即當有 n 個 shared_ptr 物件託管同乙個指標 p時,則 p 的託管計數就是 n。】

⑵ 當乙個指標的託管計數減為 0 時,該指標會被釋放。【shared_ptr 物件消亡或託管了新的指標,都會導致其原託管指標的託管計數減 1】

⑶ shared_ptr 的 reset 成員函式可以使得物件解除對原託管指標的託管(如果有的話),並託管新的指標,原指標的託管計數會減 1。

⑷ 輸出的第4行說明:用 new 建立的動態物件 a(2) 被釋放了。(程式中沒有寫 delete 語句,而 a(2) 被釋放)

是因為程式的 sp3.reset(new a(5)); 執行後,已經沒有 shared_ptr 物件去託管 a(2),於是 a(2) 的託管計數變為 0。

【最後乙個解除對 a(2) 託管的 shared_ptr 物件會去釋放 a(2)】     

⑸ main函式結束時,sp1、sp2、sp3 物件消亡,各自將其託管的指標的託管計數減為 0,並且釋放其託管的指標,於是會有以下輸出:

5 destructed

4 destructed

3 destructed

5. 拓展

注意,不能用下面的方式使得兩個 shared_ptr 物件託管同乙個指標。如: 

a* p = new a(10);

shared_ptr sp1(p), sp2(p);

sp1 和 sp2 並不會共享同乙個對 p 的託管計數,而是各自將對 p 的託管計數都記為 1 (sp2 無法知道 p 已經被 sp1 託管過)。

這樣,當 sp1 消亡時要析構 p,sp2 消亡時要再次析構 p,這會導致程式崩潰。

1. 說明

unique_ptr 獨佔所指向的物件, 同一時刻只能有乙個 unique_ptr 指向給定物件(通過禁止拷貝語義, 只有移動語義來實現)

2. 例項

std::unique_ptrp1(new int(5));

std::unique_ptrp2=p1;  // 編譯會出錯, unique_ptr 不支援賦值

std::unique_ptrp2(p1);  // 錯誤, unique_ptr 不支援拷貝

std::unique_ptrp3=std::move(p1);  // 轉移所有權,那塊記憶體歸p3所有, p1成為無效的針.

p3.reset();  //釋放記憶體.

p1.reset();  //無效

3. 成員函式

(1) get 獲得內部物件的指標, 由於已經過載了()方法, 因此和直接使用物件是一樣的.如 unique_ptrsp(new int(1)); sp 與 sp.get()是等價的

(2) release 放棄內部物件的所有權,將內部指標置為空, 返回所內部物件的指標, 此指標需要手動釋放

(3) reset 銷毀內部物件並接受新的物件的所有權(如果使用預設引數的話,也就是沒有任何物件的所有權, 此時僅將內部物件釋放, 並置為空)

(4) swap 交換兩個 shared_ptr 物件(即交換所擁有的物件)

(5) move 所有權轉移(通過移動語義)。[std::move(up); up所有權轉移後,變成「空指標」 (up 的定義為 std::unique_ptrup)]

1. 說明

weak_ptr指向乙個已經用shared_ptr進行管理的物件。

為了訪問這個物件,乙個 weak_ptr 可以通過 shared_ptr 的建構函式或是 weak_ptr 的成員函式 lock() 轉化為乙個shared_ptr。

weak_ptr 設計的目的是為配合 shared_ptr 而引入的一種智慧型指標來協助 shared_ptr 工作, 

它只可以從乙個 shared_ptr 或另乙個 weak_ptr 物件構造, 它的構造和析構不會引起引用記數的增加或減少。

weak_ptr 沒有過載*和->但可以使用 lock 獲得乙個可用的 shared_ptr 物件。 注意, weak_ptr 在使用前需要檢查合法性。

weak_ptr 支援拷貝或賦值, 但不會影響對應的 shared_ptr 內部物件的計數。

2. 成員函式

(1) expired 用於檢測所管理的物件是否已經釋放, 如果已經釋放, 返回 true; 否則返回 false。

(2) lock 用於獲取所管理的物件的強引用(shared_ptr). 如果 expired 為 true, 返回乙個空的 shared_ptr; 否則返回乙個 shared_ptr, 其內部物件指向與 weak_ptr 相同。

(3) use_count 返回與 shared_ptr 共享的物件的引用計數。

(4) reset 將 weak_ptr 置空。

3. 使用"weak_ptr"解決"shared_ptr"因迴圈引用而不能釋放資源的問題

使用 shared_ptr 時, shared_ptr 為強引用, 如果存在迴圈引用, 將導致記憶體洩露。而 weak_ptr 為弱引用, 可以避免此問題。 其原理:

對於弱引用來說, 當引用的物件活著的時候弱引用不一定存在. 僅僅是當它存在的時候的乙個引用, 弱引用並不修改該物件的引用計數, 這意味這弱引用它並不對物件的記憶體進行管理。

weak_ptr 在功能上類似於普通指標, 然而乙個比較大的區別是, 弱引用能檢測到所管理的物件是否已經被釋放, 從而避免訪問非法記憶體。

注意:雖然通過弱引用指標可以有效的解除迴圈引用, 但這種方式必須在程式設計師能預見會出現迴圈引用的情況下才能使用, 也可以是說這個僅僅是一種編譯期的解決方案, 如果程式在執行過程**現了迴圈引用, 還是會造成記憶體洩漏。

C 之智慧型指標

本文發表於1999年10月份的c c users journal,17 10 1.為什麼稱它為 自動 指標?auto ptr只是眾多可能的智慧型指標之一。許多商業庫提供了更複雜的智慧型指標,用途廣泛而令人驚異,從管理引用的數量到提供先進的 服務。可以把標準c auto ptr看作智慧型指標的ford...

C 之智慧型指標

c 中有四個智慧型指標 auto ptr,shared ptr,weak ptr,unique ptr,其中後三個是c 11支援,並且第乙個已經被c 11棄用。智慧型指標從書面意思來說,就是智慧型。主要是動態記憶體的使用很容易出問題,要在正確的時間正確釋放記憶體是很困難的。有時我們可能忘了釋放記憶體...

c 之智慧型指標

設計出乙個class像指標,但是功能更強大,分為兩種形式一種是標準庫的源 早期的指標,多半是過載 和 第二種是迭代器的智慧型指標 1.早期的智慧型指標 templateclass shared ptr t operator const shared ptr t p px p private t px...