C++智能指針原理與簡單實現(xiàn)

Java面試官經(jīng)常喜歡問關于垃圾回收的問題液肌。而他最終給出的答案往往是:給對象中添加一個引用計數(shù)器承疲,每當有一個地方引用它時,計算器值就加1冲呢;當引用失效時舍败,計數(shù)器值就減1;任何時候計數(shù)器為0的對象就是不可能再被使用的敬拓。

客觀的說邻薯,引用計數(shù)算法的實現(xiàn)簡單,判定效率也很高乘凸,在大部分情況下它都是一個不錯的算法厕诡。但是,至少主流的Java虛擬機里面沒有選用引用計數(shù)算法來管理內(nèi)存营勤,其中最主要的原因是它很難解決對象之間的相互循環(huán)引用的問題灵嫌。在主流的商用程序語言(Java、C#)的主流實現(xiàn)中通過可達性分析來判定對象存活的葛作。

這里寿羞,我們不去談可達性分析策略。至少赂蠢,引用計數(shù)算法還是有一定的用武之地的绪穆。比如說,蘋果為自家的ios開發(fā)編程語言objective-c引用了ARC機制來進行內(nèi)存管理虱岂,在很大程度上消除了手動內(nèi)存管理的負擔玖院。為了避免對象之間循環(huán)引用,我們可以將對象聲明為弱引用第岖。而在C++中司恳,內(nèi)存的分配和釋放需要手動來管理,這在一定程度上帶來了內(nèi)存泄漏的隱患绍傲。幸運的是,C++標準庫中提供了一種叫做智能指針(shared_ptrs)的類,智能指針的作用有如同指針烫饼,但會記錄有多少個shared_ptrs共同指向一個對象猎塞。這便是所謂的引用計數(shù)。一旦最后一個這樣的指針被銷毀杠纵,也就是一旦某個對象的引用計數(shù)變?yōu)?荠耽,這個對象會被自動刪除。

比如說比藻,用智能指針來創(chuàng)建一個動態(tài)分配的字符串對象:

//新創(chuàng)建一個對象铝量,引用計數(shù)器為1
shared_ptr<string> pstr(new string("abc"));

解引用一個智能指針返回它指向的對象。同樣银亲,我們可以像操作普通指針一樣調(diào)用string提供的方法慢叨。

if (pstr && pstr->empty()) {
        *pstr = "hello";
}

當有另外一個智能指針對當前智能指針進行拷貝時,引用計數(shù)器加1:

shared_ptr<string> pstr(new string("abc")); //pstr指向的對象只有一個引用者
shared_ptr<string> pstr2(pstr); //pstr跟pstr2指向相同的對象务蝠,此對象有兩個引用者

當兩個智能指針進行賦值操作時拍谐,左邊的指針指向的對象引用計數(shù)減1,右邊的加1馏段。

shared_ptr<string> pstr(new string("abc"));
shared_ptr<string> pstr2(new string("hello"));
pstr2 = pstr; //給pstr2賦值轩拨,令他指向另一個地址,遞增pstr指向的對象的引用計數(shù)院喜,遞減pstr2原來指向的對象引用計數(shù)

指針離開作用域范圍時凡蜻,同樣引用計數(shù)減1。當引用計數(shù)為0時盖文,對象被回收废士。

根據(jù)以上的分析,我們對它做一個簡單的實現(xiàn):

template <typename T>
class smart_ptrs {

public:
    smart_ptrs(T*); //用普通指針初始化智能指針
    smart_ptrs(smart_ptrs&);

    T* operator->(); //自定義指針運算符
    T& operator*(); //自定義解引用運算符
    smart_ptrs& operator=(smart_ptrs&); //自定義賦值運算符
    
    ~smart_ptrs(); //自定義析構(gòu)函數(shù)

private:
    int *count; //引用計數(shù)
    T *p; //智能指針底層保管的指針
};

跟標準庫一樣元咙,我們使用模板來實現(xiàn)它梯影。
用普通指針進行初始化時,需要將該指針進行封裝庶香,并且引用計數(shù)初始化為1甲棍。

template <typename T>
smart_ptrs<T>::smart_ptrs(T *p): count(new int(1)), p(p) {
}

定義拷貝構(gòu)造函數(shù):

template <typename T>
//對普通指針進行拷貝,同時引用計數(shù)器加1赶掖,因為需要對參數(shù)進行修改感猛,所以沒有將參數(shù)聲明為const
smart_ptrs<T>::smart_ptrs(smart_ptrs &sp): count(&(++*sp.count)), p(sp.p)  {
}

定義指針運算符:

template <typename T>
 T* smart_ptrs<T>::operator->() {
    return p;
 }

定義解引用運算符,直接返回底層指針的引用:

template <typename T>
T& smart_ptrs<T>::operator*() {
    return *p;
}

定義賦值運算符奢赂,左邊的指針計數(shù)減1陪白,右邊指針計數(shù)加1,當左邊指針計數(shù)為0時膳灶,釋放內(nèi)存:

template <typename T>
smart_ptrs<T>& smart_ptrs<T>::operator=(smart_ptrs& sp) {
    ++*sp.count;
    if (--*count == 0) { //自我賦值同樣能保持正確
        delete count;
        delete p;
    }
    this->p = sp.p;
    this->count = sp.count;
    return *this;
}

定義析構(gòu)函數(shù):

template <typename T>
smart_ptrs<T>::~smart_ptrs() {
    if (--*count == 0) {
        delete count;
        delete p;
    }
}

好了咱士,大功告成立由!接下來,我們用這段代碼進行測試:

smart_ptrs<string> pstr(new string("abc"));
smart_ptrs<string> pstr2(pstr);
smart_ptrs<string> pstr3(new string("bcd"));
pstr3 = pstr2;

為了讓測試結(jié)果更明顯序厉,我在方法中加入了一些輸出锐膜,測試結(jié)果如下:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市弛房,隨后出現(xiàn)的幾起案子道盏,更是在濱河造成了極大的恐慌,老刑警劉巖文捶,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荷逞,死亡現(xiàn)場離奇詭異,居然都是意外死亡粹排,警方通過查閱死者的電腦和手機种远,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恨搓,“玉大人院促,你說我怎么就攤上這事「В” “怎么了常拓?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辉浦。 經(jīng)常有香客問我弄抬,道長,這世上最難降的妖魔是什么宪郊? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任掂恕,我火速辦了婚禮,結(jié)果婚禮上弛槐,老公的妹妹穿的比我還像新娘懊亡。我一直安慰自己,他們只是感情好乎串,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布店枣。 她就那樣靜靜地躺著,像睡著了一般叹誉。 火紅的嫁衣襯著肌膚如雪鸯两。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天长豁,我揣著相機與錄音钧唐,去河邊找鬼。 笑死匠襟,一個胖子當著我的面吹牛钝侠,可吹牛的內(nèi)容都是我干的该园。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼机错,長吁一口氣:“原來是場噩夢啊……” “哼爬范!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弱匪,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎璧亮,沒想到半個月后萧诫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡枝嘶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年帘饶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片群扶。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡及刻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出竞阐,到底是詐尸還是另有隱情缴饭,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布骆莹,位于F島的核電站颗搂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏幕垦。R本人自食惡果不足惜丢氢,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望先改。 院中可真熱鬧疚察,春花似錦、人聲如沸仇奶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猜嘱。三九已至衅枫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朗伶,已是汗流浹背弦撩。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留论皆,地道東北人益楼。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓猾漫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親感凤。 傳聞我的和親對象是個殘疾皇子悯周,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,506評論 1 51
  • 從三月份找實習到現(xiàn)在,面了一些公司陪竿,掛了不少禽翼,但最終還是拿到小米、百度族跛、阿里闰挡、京東、新浪礁哄、CVTE长酗、樂視家的研發(fā)崗...
    時芥藍閱讀 42,184評論 11 349
  • 導讀## 最近在補看《C++ Primer Plus》第六版,這的確是本好書桐绒,其中關于智能指針的章節(jié)解析的非常清晰...
    小敏紙閱讀 1,990評論 1 12
  • 1.1 概述 Java優(yōu)點: 1夺脾、結(jié)構(gòu)嚴謹,面向?qū)ο?2茉继、擺脫硬件平臺束縛咧叭,實現(xiàn)了“一次編寫,到處運行”的理想; ...
    viciyforever閱讀 1,146評論 1 9
  • 不知是偶然還是巧然馒疹,在夏末繽紛的季節(jié)里佳簸,因眼角的余溫,不小心便被騰訊的首頁推薦《明日之子》給帶走颖变,又因剛剛好安安巧...
    芳草幽蘭閱讀 266評論 3 1