STL原始碼剖析 shared ptr

2021-08-28 16:44:01 字數 2812 閱讀 6985

目錄

一、 引言

二、 **實現 

2.1 模擬實現shared_ptr

2.2 測試用例

三、 潛在問題分析 

你可能還需要了解模擬實現c++標準庫中的auto_ptr

與auto_ptr大同小異,shared_ptr也是乙個類。可以實現多個指標指向同乙個物件(引用計數)。發生拷貝的話都指向相同的記憶體。

命名說明:為了和boost庫提供的智慧型指標shared_ptr區分開,我將模擬實現的指標命名為mshared_ptr(m是my的簡寫)。

難點一、我們知道,boost庫中提供的shared_ptr的核心就是引用計數,實現的方法不盡相同,只要能達到目的就可以了。在這裡,我採用靜態map表的方式來實現。

static map_map;        //靜態資料成員需要在類外進行初始化 

如何理解這種操作?map表建立了原生指標t* 和次數乙個對映。 如圖1所示,如果有四個mshared_ptr(自主實現)型別的變數同時指向一塊堆記憶體,map表中就會建立原生指標_ptr和4之間的乙個對映。如果有更多的變數指向該塊堆記憶體或者a、b、c、d其中有任何乙個變數析構了,都會引起引用計數的變化。

難點二、為什麼成員運算子(俗稱箭頭)的過載返回型別是原生指標的型別?這一點在模擬實現c++標準庫中的auto_ptr已經討論過了。在這裡再次討論也無妨!mshared_ptr名為指標,實際上是類。對乙個類採用成員運算子過載,返回值很自然的就是類中的成員了。

templatet* mshared_ptr::operator->()		//成員運算子過載

難點三、 

引用計數

是如何實現按需變化的?如下**所示:if語句一定會進入,是否執行還得兩說!if語句一經進入,引用計數就自減1了,在決定釋放記憶體之前,萬萬牢記:不要對null指標進行操作,這就是if語句後半部分存在的意義。這小段**在析構函式和賦值運算子過載中都出現了。值得注意一下。

if (--_map[_ptr] <= 0 && null != _ptr)

完整**段: 

#includeusing namespace std;

#includetemplateclass mshared_ptr

;templatemapmshared_ptr::_map;

templatemshared_ptr::mshared_ptr(t *ptr) //構造方法

templatemshared_ptr::~mshared_ptr() //析構方法

}templatemshared_ptr::mshared_ptr(mshared_ptr&src) //拷貝構造

templatemshared_ptr& mshared_ptr::operator=(mshared_ptr&src) //賦值運算子過載

if (--_map[_ptr] <= 0 && null != _ptr)

_ptr = src._ptr;

_map[_ptr]++;

return *this;

}templatet& mshared_ptr::operator*() //解引用運算子過載

templatet* mshared_ptr::operator->() //成員運算子過載

在多執行緒環境下,引用計數可能會出錯是不可避免的。但是通過加鎖就能解決這個問題。本篇部落格的關注點不在於多執行緒的環境下執行,故而未曾加鎖。有乙個問題,即使是boost庫中的shared_ptr不可避免,那就是——迴圈引用(交叉引用)導致記憶體洩漏。現說明如下:

mshared_ptr利用引用計數來決定是否釋放堆區的記憶體。如果存在迴圈引用的話,引用計數到最後還是會降不下去。如圖3所示,類a只有成員_ptr_b,類b只有成員_ptr_a,如果發生上述情況,在ptr_a析構的時候,僅僅會將引用計數減1而不真正釋放其所指向的記憶體;在ptr_b析構的時候也一樣,究其根源,是因為類內的指標也占用了引用計數。

class b;    //同檔案,從上至下編譯,故而需要告訴類a——類b確實存在

從執行結果我們可以看到,ptr_a和ptr_b都已被析構,但是類內的指標沒有被析構,這就是導致記憶體洩漏的罪魁禍首。如何解決這個問題,我們需要使用mshared_ptr的好搭檔——mweak_ptr。模擬實現boost庫中的weak_ptr 。

STL原始碼剖析

這兩天略讀完了 stl原始碼剖析 之所以是略讀,就是只看大體,不講具現 這個詞在 深度探析c 物件模型 中比較多 已經看過好幾本c 的書了,感覺c 本身設計的博大精深,而c 編譯器就更是乙個神奇的東西,換句話說,你永遠不知道c 編譯器揹著你做了哪些出乎你意料的事 不扯遠了 我主要是想看stl容器的具...

STL原始碼剖析

這兩天略讀完了 stl原始碼剖析 之所以是略讀,就是只看大體,不講具現 這個詞在 深度探析c 物件模型 中比較多 已經看過好幾本c 的書了,感覺c 本身設計的博大精深,而c 編譯器就更是乙個神奇的東西,換句話說,你永遠不知道c 編譯器揹著你做了哪些出乎你意料的事 不扯遠了 我主要是想看stl容器的具...

STL原始碼剖析

花了兩天時間略讀了一下 stl原始碼分析 看了個大體,對於細節並沒有深究。之所以想翻翻這本書,主要是想看看stl中的特性 介面卡的具體實現。看完之後收穫還是蠻大的,模板的各種組合讓我眼前一亮,下面大概總結一些內容。1.記憶體分配 sgi記憶體分配採用兩級實現,對於大記憶體塊的申請 大於128k 由第...