C 引用計數技術及智慧型指標的簡單實現

2021-09-07 09:46:21 字數 4241 閱讀 3349

閱讀目錄

5.智慧型指標類的改進一

6.智慧型指標改進二

正文

一直以來都對智慧型指標一知半解,看c++primer中也講的不夠清晰明白(大概是我功力不夠吧)。最近花了點時間認真看了智慧型指標,特地來寫這篇文章。

回到頂部

簡單來說,智慧型指標是乙個類,它對普通指標進行封裝,使智慧型指標類物件具有普通指標型別一樣的操作。具體而言,複製物件時,副本和原物件都指向同一儲存區域,如果通過乙個副本改變其所指的值,則通過另一物件訪問的值也會改變.所不同的是,智慧型指標能夠對記憶體進行進行自動管理,避免出現懸垂指標等情況。

回到頂部

c語言、c++語言沒有自動記憶體**機制,關於記憶體的操作的安全性依賴於程式設計師的自覺。程式設計師每次new出來的記憶體塊都需要自己使用delete進行釋放,流程複雜可能會導致忘記釋放記憶體而造成記憶體洩漏。而智慧型指標也致力於解決這種問題,使程式設計師專注於指標的使用而把記憶體管理交給智慧型指標。

我們先來看看普通指標的懸垂指標問題。當有多個指標指向同乙個基礎物件時,如果某個指標delete了該基礎物件,對這個指標來說它是明確了它所指的物件被釋放掉了,所以它不會再對所指物件進行操作,但是對於剩下的其他指標來說呢?它們還傻傻地指向已經被刪除的基礎物件並隨時準備對它進行操作。於是懸垂指標就形成了,程式崩潰也「指日可待」。我們通過**+圖來來探求懸垂指標的解決方法。

int * ptr1 = new int (1); int * ptr2 = ptr1; int * ptr3 = prt2; cout << *ptr1 << endl; cout << *ptr2 << endl; cout << *ptr3 << endl; delete ptr1; cout << *ptr2 << endl;

**簡單就不囉嗦解釋了。執行結果是輸出ptr2時並不是期待的1,因為1已經被刪除了。這個過程是這樣的:

從圖可以看出,錯誤的產生來自於ptr1的」無知「:它並不知道還有其他指標共享著它指向的物件。如果有個辦法讓ptr1知道,除了它自己外還有兩個指標指向基礎物件,而它不應該刪除基礎物件,那麼懸垂指標的問題就得以解決了。如下圖:

那麼何時才可以刪除基礎物件呢?當然是只有乙個指標指向基礎物件的時候,這時通過該指標就可以大大方方地把基礎物件刪除了。

回到頂部

如何來讓指標知道還有其他指標的存在呢?這個時候我們該引入引用計數的概念了。引用計數是這樣乙個技巧,它允許有多個相同值的物件共享這個值的實現。引用計數的使用常有兩個目的:

回到頂部

了解了引用計數,我們可以使用它來寫我們的智慧型指標類了。智慧型指標的實現策略有兩種:輔助類與控制代碼類。這裡介紹輔助類的實現方法。

首先,我們來定義乙個基礎物件類point類,為了方便後面我們驗證智慧型指標是否有效,我們為point類建立如下介面:

class point                                       

intgetx() const intgety() const voidsetx(intxval) voidsety(intyval) private: int x, y; };

在建立智慧型指標類之前,我們先建立乙個輔助類。這個類的所有成員皆為私有型別,因為它不被普通使用者所使用。為了只為智慧型指標使用,還需要把智慧型指標類宣告為輔助類的友元。這個輔助類含有兩個資料成員:計數count與基礎物件指標。也即輔助類用以封裝使用計數與基礎物件指標

class u_ptr                                  

~u_ptr() int count; point *p; };

做好前面的準備後,我們可以來為基礎物件類point書寫乙個智慧型指標類了。根據引用計數實現關鍵點,我們可以寫出我們的智慧型指標類如下:

class smartptr

smartptr(const smartptr &sp) :rp(sp.rp) smartptr& operator=(const smartptr& rhs) ~smartptr() private: u_ptr *rp; };

至此,我們的智慧型指標類就完成了,我們可以來看看如何使用

intmain()  //此時count=2 } //此時count=1; } //此時count=0;pa物件被delete掉 cout << pa->getx ()<< endl; system("pause"); return 0; }

來看看執行結果咯:

還有2個指標指向基礎物件

還有1個指標指向基礎物件

-17891602

請按任意鍵繼續. . .

如期,在離開大括號後,共享基礎物件的指標從3->2->1->0變換,最後計數為0時,pa物件被delete,此時使用getx()已經獲取不到原來的值。

回到頂部

雖然我們的smartptr類稱為智慧型指標,但它目前並不能像真正的指標那樣有->、*等操作符,為了使它看起來更像乙個指標,我們來為它過載這些操作符。**如下所示:

smartptr(const smartptr &sp) :rp(sp.rp)  smartptr& operator=(const smartptr& rhs)  ~smartptr()  point & operator *() //過載*操作符  point* operator ->() //過載->操作符  private: u_ptr *rp; };

然後我們可以像指標般使用智慧型指標類

point *pa = new point(10, 20); smartptr sptr1(pa); //像指標般使用 cout

回到頂部

目前這個智慧型指標智慧型用於管理point類的基礎物件,如果此時定義了個矩陣的基礎物件類,那不是還得重新寫乙個屬於矩陣類的智慧型指標類嗎?但是矩陣類的智慧型指標類設計思想和point類一樣啊,就不能借用嗎?答案當然是能,那就是使用模板技術。為了使我們的智慧型指標適用於更多的基礎物件類,我們有必要把智慧型指標類通過模板來實現。這裡貼上上面的智慧型指標類的模板版:

//模板類作為友元時要先有宣告

template

class smartptr;

template class u_ptr //輔助類 //析構函式 ~u_ptr() //引用計數 int count; //基礎物件指標 t *p; }; template class smartptr //智慧型指標類 //建構函式 smartptr(const smartptr&sp) :rp(sp.rp) //複製建構函式 smartptr& operator=(const smartptr& rhs) t & operator *() //過載*操作符 t* operator ->() //過載->操作符 ~smartptr() private: u_ptr*rp; //輔助類物件指標 };

好啦,現在我們能夠使用這個智慧型指標類物件來共享其他型別的基礎物件啦,比如int:

intmain()  } } system("pause"); return 0; }

執行結果如期所願,smartptr類管理起int型別來了:

2

20還有2個指標指向基礎物件

還有1個指標指向基礎物件

請按任意鍵繼續. . .

c 引用計數實現簡單智慧型指標

使用智慧型指標類 輔助類 原始指標實現 輔助類 儲存引用計數和原始指標,智慧型指標型別為友元 將原來儲存在智慧型指標中的內部結構體移出來形成單獨類,智慧型指標內部不用儲存這個類的指標,通過友元來訪問這個類中成員。智慧型指標 初始化,析構,拷貝賦值,複製函式,過載 過載 通過智慧型指標的成員函式來操作...

c 實現引用計數智慧型指標

主要的思路是使用乙個int 的指標進行計數,在建構函式時候設定為0,並加1 或者直接設定為1 然後賦值和複製構造時候把int 和資料儲存的指標t mp傳到另外乙個類中。在賦值的時候要注意左邊的指標是否已經有資料了,有資料就要先 1,然後再進行賦值。template class ref1 ref1 c...

引用計數與智慧型指標

c 沒有完善的gc機制,直到c 11才在stl中正式引入了智慧型指標。出現在庫中說明智慧型指標不是語言特性。c 智慧型指標實現了部分自動記憶體管理的目的。引用計數是使用資源管理函式 構造析構複製等函式 和作用域原理實現的。每塊動態分配的記憶體 堆記憶體 都維護乙個相應的計數器,來記錄指向該記憶體的變...