1. 程式人生 > >c++自動釋放的指標之——auto_ptr和shared_ptr

c++自動釋放的指標之——auto_ptr和shared_ptr

假設我們使用一個用來塑模投資行為(例如股票、債券等)的程式庫,其中各式各樣的投資型別整合自一個root class Investment:

class Investment { ... };//"投資型別"整合體系中的root class

進一步假設,這個程式庫通過一個工廠模式供應我們某特定的Investment物件:

Investment* createInvestment();
//返回指標,指向Investment繼承體系內的動態分配物件。呼叫者有責任刪除它,這裡為了簡化,刻意不寫引數。

createInvesment的呼叫端使用了函式返回的物件後,有責任刪除之,現在考慮有個f函式履行了這個責任:

void f()
{
    Investment* pInv = createInvesment();//呼叫factory函式
    。。。
    delete pInv;
}

這看起來妥當,但若干情況下f可能無法刪除pInv這個指標由於函式之中有某些return語句直接結束了這個函式,那麼delete就不會發生,之後我們洩露的不只是內含投資物件的那塊記憶體,還包括那些投資物件所儲存的任何資源。

為確保createInvestment返回的資源總是被釋放,我們需要將資源放進物件內,當控制流離開f,該物件的解構函式會自動釋放那些資源。把資源放進物件內,我們便可依賴c++的“解構函式自動呼叫機制”確保資源被釋放。標準程式庫提供的auto_ptr正是針對這種形式而設計的特製產品。auto_ptr是個“類指標物件

”,也就是所謂的智慧指標,其解構函式自動對其物件呼叫delete。下面示範如何使用auto_ptr以避免f函式潛在的資源洩露的可能性:

void f()
{
    std::auto_ptr<Investment> pInv(createInvestment());
    ...
    //呼叫factory函式,一如既往的使用pInv,經由auto_ptr的解構函式自動刪除pInv
}

這簡單的例子示範“以物件管理資源”的兩個關鍵想法:

1、獲得資源後獲得立即放進管理物件內,即上述使用的auto_ptr指標,自動釋放。

2、管理物件運用解構函式確保資源被釋放,即自己實現一個類似auto_ptr指標的物件,在裡面運用實現析構來delete

由於auto_ptr被銷燬時會自動刪除它所指之物,所以一定要注意別讓多個auto_ptr同時指向同一物件。如果真是那樣,物件會被刪除一次以上,為了預防這個問題,auto_ptr有一個不同尋常的特質:

若通過copy建構函式或copy assignment操作符複製它們,它們會變成null,而複製所得的指標將取得資源的唯一擁有權!

std::auto_ptr<Investment> pInv1(createInvestment());//pInv1指向物件

std::auto_ptr<Investment> pInv2(pInv1);//pInv2指向物件,pInv1指向null

pInv1 = pInv2;pInv1指向物件,pInv2指向null

auto_ptr的代替方案是“引用技術型智慧指標”tr1::shared_ptr,它能持續追蹤共有多少個物件指向某筆資源,並在無人指向它時自動刪除該資源。

void f()
{
    ...
    std::trl::shared_ptr<Investment> pInv(createInvestment());
    //呼叫factory函式,使用pInv一如既往,經由shared_ptr解構函式自動刪除pInv
    ...
}

這段程式碼看起來和auto_ptr那個版本相同,但shared_ptr的複製行為確實正常的,它不會因為複製而使原來的指標指向null。

問題:

auto_ptr和tr1::shared_ptr兩者都在其析構中做delete而不是delete[],那意味在動態分配而得的array身上使用auto_ptr和tr1::shared_ptr是個餿主意。儘管如此,可嘆的是,編譯器仍能夠通過編譯:

std::auto_ptr<std::string> aps(new std::string[10]);//會用錯誤的delete形式
std::tr1::shred_ptr<int> spi(new int[1024]);//同上

綜上所述:

如果打算手工釋放資源(例如使用delete而非使用一個資源管理類),容易發生某些錯誤。灌裝式的資源管理類如auto_ptr和tr1::shared_ptr往往比較輕鬆的遵循上面的忠告,但是這又存在著別的問題,所以就需要精巧的設計你自己的資源管理類。那並不是很困難。最後需要強調的是——咱們要學會“以物件管理資源”!!!