使用智能指針是C++中常用的管理內(nèi)存的方式。關(guān)于智能指針的設(shè)計(jì),各路C++高手也是各展神通。
在1994年. Greg Colvin向C++標(biāo)準(zhǔn)委員會(huì)提出了自己設(shè)計(jì)的智能指針:auto_ptr和counted_ptr。auto_ptr實(shí)現(xiàn)基本的RAII管理,不可復(fù)制;counted_ptr采用引用計(jì)數(shù)實(shí)現(xiàn)了一個(gè)可復(fù)制的智能指針。兩者用于不同的場合。
但是標(biāo)準(zhǔn)委員會(huì)最終只通過了auto_ptr,并且對auto_ptr加入了一個(gè)古怪的“所有權(quán)轉(zhuǎn)移”語義。后來auto_ptr和counted_ptr進(jìn)入了Boost C++ 庫,改名為scoped_ptr和shared_ptr。
std::auto_ptr只所以設(shè)計(jì)為可拷貝的,也許是出于以下考慮,比如下例函數(shù):
void f1(object* ptr);
object* f2();
f1中的參數(shù)所指向的對象應(yīng)該由誰來刪除呢?調(diào)用者還是被調(diào)用者?如果不看程序文檔的話,無法知道這一點(diǎn)。f2函數(shù)也存在同樣的問題。
用auto_ptr可以消除這種歧義性:
void f1(auto_ptr<object> ptr);
auto_ptr<object> f2();
盡管如此,auto_ptr的“所有權(quán)轉(zhuǎn)移”語義還是會(huì)帶來副作用,因?yàn)闀?huì)修改原值的常量拷貝違背了一般的設(shè)計(jì)原則,它也許會(huì)在你意想不到的情況下就把對象轉(zhuǎn)移了。它也不能用于標(biāo)準(zhǔn)容器中。
所以auto_ptr在新的標(biāo)準(zhǔn)庫已經(jīng)不再推薦使用。取而代之的是unique_ptr。unique_ptr與auto_ptr類似,但限制了auto_ptr的拷貝行為。同時(shí),像上面舉的例子一樣,unique_ptr可以作為函數(shù)的參數(shù)和返回值使用。這是因?yàn)镃++增加了一個(gè)新的特征:右值引用。
shared_ptr也進(jìn)入了標(biāo)準(zhǔn)庫。對于引用計(jì)數(shù)的智能指針而言,循環(huán)引用是一個(gè)大問題。標(biāo)準(zhǔn)庫為此把shared_ptr定義為強(qiáng)引用指針,它還實(shí)現(xiàn)了一個(gè)弱引用指針weak_ptr。顯然,標(biāo)準(zhǔn)庫并沒有從根本上解決循環(huán)引用的問題,它把這個(gè)問題交給了程序員。在一個(gè)簡單的系統(tǒng)中,你可以區(qū)分使用shared_ptr和weak_ptr,以此來避免出現(xiàn)循環(huán)引用。但是在一個(gè)大的對象系統(tǒng)中,有時(shí)還是容易出錯(cuò)。循環(huán)引用的問題,嚴(yán)重減弱了shared_ptr的可用性。
那么能不能自動(dòng)檢測是否出現(xiàn)循環(huán)引用呢?事實(shí)上,對于shared_ptr這種使用非侵入式策略實(shí)現(xiàn)的智能指針,是很難實(shí)現(xiàn)自動(dòng)檢測的。但是如果采用侵入式設(shè)計(jì),我們可以引入一些接口,來解決這個(gè)問題。循環(huán)引用的檢測,實(shí)際上是圖論中的回路檢測問題。
本文由eXile 原創(chuàng),轉(zhuǎn)載請表明原貼地址。 http://m.shnenglu.com/eXile/。