c 智慧型指標的理解

2021-08-14 09:13:33 字數 3451 閱讀 6982

智慧型指標的運用是c++裡很重要的乙個方面。

智慧型指標是為了更容易的動態的管理和使用動態記憶體而設計的,新的標準庫提供兩種智慧型指標。

乙個是shared_ptr 允許多個指標指向同乙個物件

乙個是unique_ptr 獨佔所指向的物件。

還有一種伴隨類 weak_ptr 他是一種弱引用 指向shared_ptr所指向的物件。

這些型別都定義在memory標頭檔案當中。

智慧型指標類似容器也是模板,當我們建立乙個智慧型指標時候也需要給出指標所指向的物件的型別,這個在智慧型指標的模板引數當中給出。

shared_ptr

p;

這就是宣告了乙個指向string型別的智慧型指標 預設初始化的智慧型指標儲存的是乙個空指標(預設無參建構函式)。智慧型指標的使用和一般的指標是一樣的,解引用操作符使得返回指標指向的物件。條件判斷乙個指標就是判斷這個指標是否為空。

智慧型指標一樣支援指標的->獲得成員變數指向成員函式的操作符。(都已經過載)

智慧型指標支援所有一般指標的操作但是也具備智慧型指標獨有的操作:

make_shared(args) 返回乙個shared_ptr指向乙個型別為t的物件,使用args初始化物件

shared_ptrp(q) p是q的拷貝 q的計數器增加、

p = q 遞減p的計數器 遞增q的計數器

p.unique()

p.use_count()

最安全的分配和使用動態記憶體的額方式是使用make_shared的標準庫函式、

這個函式在定義乙個動態指標的同時分配乙個物件並且初始化他

使用乙個auto 物件來儲存make_shared 的結果這種方式比較簡單

每乙個shared_ptr都有乙個與之相關聯的計數器稱為引用計數器。

無論何時我們拷貝乙個shared_ptr都會使得計數器遞增。

當時用乙個智慧型指標去初始化另乙個智慧型指標的時候

當講其作為乙個引數傳遞給乙個函式的時候

作為函式返回值的時候

所關聯的計數器就會增加。

當我們給乙個shared_ptr 賦予乙個新的值的時候

或者當前的智慧型指標被銷毀 (離開其作用域)

計數器就會減一

一旦乙個智慧型指標的計數器變為0 那麼就會自動的釋放自己所管理的物件

當銷毀此物件的時候是通過析構函式完成銷毀的工作。

析構函式就是釋放物件分配的資源

智慧型指標的析構函式會遞減指向物件的引用計數,如果引用計數變為0 智慧型指標的析構函式就會銷毀該物件

釋放其占有的記憶體。

乙個簡易、通用的智慧型指標,它不包含所有的小技巧,不像專用的或高效能的智慧型指標那麼奢華,但是它可以很好的完成許多普遍的工作,它很適合日常性的使用。

auto_ptr所做的事情,就是動態分配物件以及當物件不再需要時自動執行清理。

void f()  

如果f()函式只有三行並且不會有任何意外,這麼做可能挺好的。

但是如果f()從不執行delete語句,或者是由於過早的返回,或者是由於執行函式體時丟擲了異常,那麼這個被分配的物件就沒有被刪除,從而我們產生了乙個經典的記憶體洩漏

這裡採用的是new的方式構造那麼是在堆上構造的只有顯示的呼叫delete才能析構該物件 否則永遠都不能釋放該物件的記憶體。

解決方案:能讓示例安全的簡單辦法是把指標封裝在乙個「智慧型的」類似於指標的物件裡,這個物件擁有這個指標並且能在析構時自動刪除這個指標所指的物件。因為這個智慧型指標可以簡單的當成乙個自動的物件(它出了作用域時會自動毀滅),所以很自然的把它稱之為「智慧型」指標。

void f()  

// 當pt出了作用域時析構函式被呼叫,從而物件被自動刪除

現在**不會洩漏t型別的物件,不管這個函式是正常退出還是丟擲了異常,因為pt的析構函式總是會在出棧時被呼叫,清理會自動進行。

最後,使用乙個auto_ptr就像使用乙個內建的指標一樣容易,而且如果想要「撤銷」資源,重新採用手動的所有權,我們只要呼叫release()。

現在將new的物件使用乙個智慧型指標進行管理,智慧型指標在離開作用域,出棧的時候會自動呼叫析構函式,析構所指向的物件。

auto_ptr實現關鍵點:

1. 利用特點「棧上物件在離開作用範圍時會自動析構」。

2. 對於動態分配的記憶體,其作用範圍是程式設計師手動控制的,這給程式設計師帶來了方便但也不可避免疏忽造成的記憶體洩漏,畢竟只有編譯器是最可靠的。

3. auto_ptr通過在棧上構建乙個物件a,物件a中wrap了動態分配記憶體的指標p,所有對指標p的操作都轉為對物件a的操作。而在a的析構函式中會自動釋放p的空間,而該析構函式是編譯器自動呼叫的,無需程式設計師操心。

不要誤用auto_ptr

1)auto_ptr不能共享所有權,即不要讓兩個auto_ptr指向同乙個物件。

2)auto_ptr不能指向陣列,因為auto_ptr在析構的時候只是呼叫delete,而陣列應該要呼叫delete。

3)auto_ptr只是一種簡單的智慧型指標,如有特殊需求,需要使用其他智慧型指標,比如share_ptr。

4)auto_ptr不能作為容器物件,stl容器中的元素經常要支援拷貝,賦值等操作,在這過程中auto_ptr會傳遞所有權,那麼source與sink元素之間就不等價了。

用法一:  

std:

:auto_ptrm_example(new myclass());

用法二:

std:

:auto_ptrm_example;

m_example.reset(new myclass());

用法三(指標的賦值操作):

std:

:auto_ptrm_example1(new myclass());

std:

:auto_ptrm_example2(new myclass());

m_example2=m_example1;

在c++中,應絕對避免把auto_ptr放到容器中。即應避免下列**:

vector

>m_example;

當用演算法對容器操作的時候,你很難避免stl內部對容器中的元素實現賦值傳遞,這樣便會使容器中多個元素被置位null,而這不是我們想看到的。

要避免這個問題,可以考慮使用採用了引用計數的智慧型指標,例如boost::shared_ptr等。auto_ptr不會降低程式的效率,但auto_ptr不適用於陣列,auto_ptr根本不可以大規模使用。 shared_ptr也要配合weaked_ptr,否則會很容易觸發迴圈引用而永遠無法**記憶體。 理論上,合理使用容器加智慧型指標,c++可以完全避免記憶體洩露,效率只有微不足道的下降(中型以上程式最多百分之一)。

c 智慧型指標

auto prt 它是 它所指向物件的擁有者 所以當自身物件被摧毀時候,該物件也將遭受摧毀,要求乙個物件只有乙個擁有者,注意 auto prt 不能使用new 來分配物件給他 include include using namespace std template void bad print au...

c 智慧型指標

很久沒寫部落格了,不知道如何表達了,哈哈.我先介紹一下深淺拷貝.class copy 此時a.ptr和b.ptr指向同乙個物件,當我們delete a.ptr時 b.ptr所指向的物件已經不存在了,要是我們引用b.ptr指向的物件也就會出問題了.深拷貝 把a.ptr所指向的物件拷貝乙份給b.ptr ...

c 智慧型指標

記得前不久有一次面試被問到智慧型指標的實現,當時對智慧型指標只是聽說但沒有了解過,就亂七八糟地說了一遍。今天寫了一遍智慧型指標,用了引用計數的概念。主要思想就是,用乙個新類對原本需要的型別進行了一層封裝,這個新類中儲存了原本的物件指標和乙個引用計數的指標,之所以全部用指標來儲存,就是因為會出現多個新...