智能指標(一):STL auto_ptr實現原理

來源:互聯網
上載者:User
文章目錄
  • 1.最精簡版本
  • 2.改進版本(重載運算子使類用起來像指標)
  • 3.完善版本(複製構造)

智能指標實際上是一個類(class),裡面封裝了一個指標.它的用處是啥呢?

指標與記憶體

說到指標自然涉及到記憶體.我們如果是在堆棧(stack)中分配了記憶體,用完後由系統去負責釋放.如果是自訂類型,就會自動的去調用你的解構函式.

但如果是在堆(heap)中分配了記憶體,也就是用malloc或者new.那隻能自動手動的使用free或delete去釋放.所以使用heap時處理的不好很容易出現啥記憶體泄露(記憶體沒有釋放掉).或者如果你delete一次了,但沒讓它賦值為0,然後再delete一次就導致未定義行為了.

於是你想如果系統能也像管理stack一樣來管理你的heap地區.不用再擔心記憶體的分配與釋放該多好啊.事實上Java,C#都這樣去做了.也給你去管理heap地區了(所有的自訂類型執行個體化時都去heap地區擷取記憶體了.也沒於提供指標的功能.你想自己去釋放記憶體都不給你這機會了.JVM或者CLR會在後台自動的去給你釋放掉那些不用的記憶體.當然這樣一來效率自然沒有你手動釋放來的高了.)

假如有一個指標指向一塊分配的記憶體,智能指標就是把該指標封裝起來,然後用完了會自動去釋放記憶體(通過智能指標類的解構函式).這樣你就不用擔心沒有去釋放記憶體了.當然並不是說你使用了智能指標就能像使用Java,C#一樣不用再擔心記憶體問題了.智能指標在使用的時候還會存在很多的問題.

據說JVM,CRL也是用(c與c++)實現的.不知道那裡面也有用到智能指標不.

 

智能指標的實現

如果你自己要封裝一個指標你會咋整呢?來來個初稿瞧瞧

1.最精簡版本

template< class T>

class my_auto_ptr {

public:

  T* m_ptr;  //被封裝的指標

public:

 my_auto_ptr( T* p) :m_ptr( p ) { }   //建構函式

 ~my_auto_ptr() { delete m_ptr; }     //解構函式

}

上面的自然是最精簡版的,只一個成員變數,建構函式和析造函數.不過雖然簡單其實也能拿來用了啊.比如:

my_auto_ptr<int> myPtr( new int(88) ); //等價int* ip = new int(88); 但這樣你得手動delete ip;而用了智能指標就不用手動delete了.

cout<< *myPtr.m_ptr;   //相當於cout<<*ip;

 

2.改進版本(重載運算子使類用起來像指標)

上面的的精簡版本用起來還挺麻煩.我們是希望封裝了指標類用起來跟指標本身一樣才好.所以需要重載-> , * 等運算子

template< class T>

class my_auto_ptr {

private:

T* m_ptr; //被封裝的指標

public:

my_auto_ptr( T* p) :m_ptr( p ) { }

~my_auto_ptr() { delete m_ptr; }

T& operator*() { return *m_ptr;}

T*  operator->() { return m_ptr;}

}

現在my_auto_ptr可以變得很像指標了

my_auto_ptr<int> mp(new int(88) );   //等價int* ip = new int(88);

int num = *mp;   //等價int num = *ip;

假如有這樣的類struct Arwen { void Test() { cout<"i am arwen"<<; }

則my_auto_ptr<Arwen> mp( new Arwen);   //等價Arwen* ip = new Arwen;

  mp->Test();  //等價ip-Test();

 

 

3.完善版本(複製構造)

一個完善點的類往往還涉及到複製構造的一些操作.也可以做把另外一個智能指標類做為建構函式的參數,或者通過=給一個類賦值

template< class T>

class my_auto_ptr {

private:

T* m_ptr;

T* GetPtr(){ //供構造賦值時使用

T* tmp = m_ptr;

m_ptr = 0;

return tmp;

}

public:

explicit my_auto_ptr( T* p = 0) :m_ptr( p ) { }

~my_auto_ptr() { delete m_ptr; }

T& operator*() { return *m_ptr;}

T* operator->() { return m_ptr;}

 

my_auto_ptr(my_auto_ptr& mp){   //複製建構函式

m_ptr = mp.GetPtr(); //mp複製過來後它自己原來的指標相當於失效了.

}

my_auto_ptr& operator=(my_auto_ptr& ap){ 造型賦值操作符

if(ap != *this)

{

delete m_ptr;

m_ptr = ap.GetPtr();

}

return *this;

}

 

void reset(T* p){  //指標重設,相當於把指標指向另外一個地方去

if(p != m_ptr)

delete m_ptr;

m_ptr = p;

}

};

 

使用舉例:

如有類struct Arwen{

int age;

Arwen(int gg) :age(gg) { };

};

 

void main()

{

 my_auto_ptr<Arwen> myPtr( new Arwen(24) );

int num =myPtr->age; //正確

 

 my_auto_ptr<Arwen> ptrOne( myPtr);  //複製構造

 //num =myPtr->age; 該處會出錯.因為把myPtr複製給ptrOne後,它自己本身相當於失效了

  num = ptrOne->age; //正確

 

 my_auto_ptr<Arwen> ptrTwo = ptrOne;

 //num = ptrOne->age;該處也會出錯,此時ptrOne也失效了

 num = ptrTwo->age; //正確

 

Arwen* pArwen = new Arwen( 88 );

ptrTwo.reset( pArwen);

num = pArwen->age; //此處的值是88了,而不是以前的24

 

return 0;

}

 

 

auto_ptr的缺陷

上面我實現的my_auto_ptr基本上是實現了auto_ptr的所有核心功能.從裡面我們可以明顯的看到一個很大缺陷.我們看到當通過複建構函式,通過操作符=賦值後,原來的那個智能指標對象就失效了.只有新的智能指標對象可以有效使用了.用個專業點的說法叫所有權的轉移.被封裝的指標指向的記憶體塊就像是一份獨享佔用的財產,當通過複製構造,通過=賦值傳給別的智能指標對象時,原有的對象就失去了對那塊記憶體地區的擁有權.也就是說任何時候只能有一個智能指標對象指向那塊記憶體地區,不能有兩個對象同時指向那塊記憶體地區.

這樣一來auto_ptr不能做為STL中容器的元素,為啥呢? 因為容器中經常存在值拷貝的情況嘛,把一個容器物件直接賦值給另一對象.完了之後兩個容器物件可得都能用啊.而如果是auto_ptr的話顯然賦值後只能一個有用,另一個完全報廢了.另外比如你有個變數auto_ptr<int> ap( new int(44) );  然後ap被放進一個容器後,ap就報廢不能用了.

不過沒辦法啊,在c++ 11標準之前,現在我們大部分用的是98標準吧,STL裡面只有auto_ptr這一種智能指標.而在11標準中除了auto_ptr還有如下三種:

 

unique_ptr

smart pointer with unique object ownership semantics

只能有一個主人的指標,可以用於STL容器

shared_ptr

smart pointer with shared object ownership semantics

可共用的指標

weak_ptr

weak reference to an object managed by std::shared_ptr

弱引用指標

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.