C 學習筆記 22

2021-08-08 10:25:13 字數 3325 閱讀 8806

在c++中, auto_ptr是乙個類,它用來實現對動態分配物件的自動釋放。

建構函式與析構函式:auto_ptr在構造時獲取對某個物件的所有權(ownership), 在析構時釋放該物件。我們可以這樣使用auto_ptr來提高**安全性,類似下面的**。

int*p=new

int(0);

auto_ptr

ap(p);

從此我們不必關心應該何時釋放p,也不用擔心發生異常會有記憶體洩漏。這裡我們有幾點要注意:

1) 因為auto_ptr析構的時候肯定會刪除他所擁有的那個物件,所以我們就要注意了,乙個蘿蔔乙個坑,兩個auto_ptr不能同時擁有同乙個物件。像這樣:

int*p=new

int(0);

auto_ptr

ap1(p);

auto_ptr

ap2(p);

因為ap1與ap2都認為指標p是歸它管的,在析構時都試圖刪除p, 兩次刪除同乙個物件的行為在c++標準中是未定義的。所以我們必須防止這樣使用auto_ptr。

2) 考慮下面這種用法:

int*pa=new

int[10];

auto_ptr

ap(pa);

因為auto_ptr的析構函式中刪除指標用的是delete,而不是delete ,所以我們不應該用auto_ptr來管理乙個陣列指標。

4) 因為c++保證刪除乙個空指標是安全的, 所以我們沒有必要把析構函式寫成:

~auto_ptr()throw()

5) 拷貝構造與賦值

與引用計數型智慧型指標不同的,auto_ptr要求其對」裸」指標的完全占有性。也就是說乙個」裸」指標不能同時被兩個以上的auto_ptr所擁有。那麼,在拷貝構造或賦值操作時,我們必須作特殊的處理來保證這個特性。auto_ptr的做法是」所有權轉移」,即拷貝或賦值的源物件將失去對」裸」指標的所有權,所以,與一般拷貝建構函式,賦值函式不同, auto_ptr的拷貝建構函式,賦值函式的引數為引用而不是常引用(const reference)。當然,乙個auto_ptr也不能同時擁有兩個以上的」裸」指標,所以,拷貝或賦值的目標物件將先釋放其原來所擁有的物件。

這裡的注意點是:

1.因為乙個auto_ptr被拷貝或被賦值後, 其已經失去對原物件的所有權,這個時候,對這個auto_ptr的提領(dereference)操作是不安全的。如下:

int*p=new

int(0);

auto_ptr

ap1(p);

auto_ptr

ap2=ap1;

cout

<<*ap1;//錯誤,此時ap1只剩乙個null指標在手了

這種情況較為隱蔽的情形出現在將auto_ptr作為函式引數按值傳遞,因為在函式呼叫過程中在函式的作用域中會產生乙個區域性物件來接收傳入的auto_ptr(拷貝構造),這樣,傳入的實參auto_ptr就失去了其對原物件的所有權,而該物件會在函式退出時被區域性auto_ptr刪除。如下:

void f(auto_ptr

ap)auto_ptr

ap1(new

int(0));

f(ap1);

cout

<<*ap1;//錯誤,經過f(ap1)函式呼叫,ap1已經不再擁有任何物件了。

因為這種情況太隱蔽,太容易出錯了,所以auto_ptr作為函式引數按值傳遞是一定要避免的。或許大家會想到用auto_ptr的指標或引用作為函式引數或許可以,但是仔細想想,我們並不知道在函式中對傳入的auto_ptr做了什麼, 如果當中某些操作使其失去了對物件的所有權, 那麼這還是可能會導致致命的執行期錯誤。

也許,用const reference的形式來傳遞auto_ptr會是乙個不錯的選擇。

建議參考auto_ptr提供的原始碼,總的來說這個智慧型指標不太好用,更好用的是share_ptr。

出現原因:auto_ptr由於它的破壞性複製語義,無法滿足標準容器對元素的要求,因而不能放在標準容器中;如果我們希望當容器析構時能自動把它容納的指標元素所指的物件刪除時,通常採用一些間接的方式來實現,顯得比較繁瑣。boost庫中提供了一種新型的智慧型指標shared_ptr,它解決了在多個指標間共享物件所有權的問題,同時也滿足容器對元素的要求,因而可以安全地放入容器中。

shared_ptr最初實現於boost庫中,後來被c++標準委員會收錄於tr1技術報告中,成為c++11標準的一部分。

shared_ptr是一種智慧型指標(smart pointer),作用有如同指標,但會記錄有多少個shared_ptrs共同指向乙個物件。這便是所謂的引用計數(reference counting)。一旦最後乙個這樣的指標被銷毀,也就是一旦某個物件的引用計數變為0,這個物件會被自動刪除。這在非環形資料結構中防止資源洩露很有幫助。

參考shared_ptr 寫的很詳細。

總的來說,auto_ptr和shared_ptr的差別就在於複製性語義,後者有乙個計數指標,更加方便的使用。

shared_ptr 的執行緒安全級別和內建型別、標準庫容器、std::string 一樣:

1、乙個 shared_ptr 物件實體可被多個執行緒同時讀取;

2、兩個 shared_ptr 物件實體可以被兩個執行緒同時寫入,「析構」算寫操作;

3、如果要從多個執行緒讀寫同乙個 shared_ptr 物件,那麼需要加鎖。

因為 shared_ptr 有兩個資料成員,讀寫操作不能原子化,使得多執行緒讀寫同乙個 shared_ptr 物件需要加鎖。

迴圈引用是指進行了自引用,引用計數增加所致(類似死鎖),計數器不會降低為0,也不會呼叫析構函式,會造成記憶體洩漏。解決辦法:引入weak_ptr弱引用指標即可解決迴圈引用問題。weak_ptr不會修改引用計數。

weak_ptr是為了配合shared_ptr而引入的一種智慧型指標,它指向乙個由shared_ptr管理的物件而不影響所指物件的生命週期,也就是將乙個weak_ptr繫結到乙個shared_ptr不會改變shared_ptr的引用計數。不論是否有weak_ptr指向,一旦最後乙個指向物件的shared_ptr被銷毀,物件就會被釋放。從這個角度看,weak_ptr更像是shared_ptr的乙個助手而不是智慧型指標。

要解決環形引用的問題,沒有特別好的辦法,一般都是在可能出現環形引用的地方使用weak_ptr來代替shared_ptr。

參考這個鏈結c++11智慧型指標之weak_ptr。

C 學習筆記22 LINQ

查詢表示式 linq 簡介 linq是language integratedquery的簡稱,它是整合在.net程式語言中的一種特性。已成為程式語言的乙個組成部分,在編寫程式時可以得到很好的編譯時語法檢查,豐富的元資料,智慧型感知 靜態型別等強型別語言的好處。並且它同時還使得查詢可以方便地對記憶體中...

Python學習筆記 22

物件導向三大特徵及作用 多型我自己簡單總結一句話 使用方法 或者其他 時,不用考慮物件型別,適用性強,比如常見的len 多型 狗 哈士奇,泰迪,金毛。乙個物件可以以不同的形態去呈現 classa def init self,name self.name name property defname s...

學習筆記2 2續

定義 dp i 1 j 前i種數字是否能構成j 為了用前i種數字加和成j,也就需要能用前i 1種數字加和成j,j ai,j mi x ai中的某一種。我們可以定義如下遞推關係 dp i 1 k 0 k mi且k x ai j時存在dp i j k x ai 為真的k int n,k,a maxn m...