C++中的動態記憶體與智慧指標

christian發表於2014-01-19

在C++中,我們通過new(在動態記憶體中為物件分配空間並初始化物件)和delete(銷燬該物件,並釋放記憶體)直接分配和釋放動態記憶體。

如下程式碼:

有些人有這樣的疑問,指標一定要new嗎?其實指標和new沒有什麼關係。這裡的new在動態記憶體裡為物件分配了記憶體空間,並返回了一個指向該物件的指標。new是申請堆空間,不是在棧上分配記憶體,指標只要指向有效的記憶體空間就可以。比如:

new直接初始化對

象:

new分配const物件必須進行初始化,並且返回的是一個指向const物件的指標:

當然new申請記憶體分配的時候也不是都會成功的,一旦一個程式用光了他的所有可用記憶體(雖然這種情況一般很少發生),new表示式就會失敗。這時候會丟擲bad_alloc異常。所以我們需要通過delete來釋放佔用的記憶體。在這裡注意delete並不是要刪除指標,而是釋放指標所指的記憶體。

使用new和delete來管理動態記憶體常出的一些錯誤:

1.忘記delete,即導致了“記憶體洩漏”,

2.野指標。在物件已經被釋放掉之後,(這裡注意,此時的指標成為了懸垂指標,即指向曾經存在的物件,但該物件已經不再存在。結果未定義,而且難以檢測。)這時候我們再次使用,會產生使用非法記憶體的指標。

不過如果我們需要保留指標,可以在delete以後將nullptr賦予指標,這樣指標就不指向任何物件了,如下程式碼:

 

題外話:在測試這個問題的時候,我輸出了下q的值發現還是42,並且沒有報錯,後來在delete p之後,我又給*p = 19;這個時候 p ,q的值在輸出的時候都是19,也沒有報錯。這個程式碼其實根本就是錯誤的了,因為p,q已經沒有有效的記憶體空間了。這裡是釋放了記憶體,但指標的值不變,指向的記憶體不會清0,指向的這片記憶體區域是待分配的,如果沒有被其他資料覆蓋的話,你就能幸運得輸出這主要原因是你分配的記憶體小,沒有繼續分配,被佔用的概率小所致。我用的xcode,換到VS下就正常報錯了,是因為VS為了從編譯器的角度上解決緩衝區溢位等問題,加上的這種功能,C++標準裡面沒有這麼要求,所有xcode和gcc是不會檢查的。所以在這裡 建議大家寫純C++程式碼的時候用vs。

3.重複delete,就會使自由空間遭到破壞如:

雖然顯示的管理記憶體在效能上有一定的優勢,但是隨著多執行緒程式的出現和廣泛使用,記憶體管理不佳的的情況變得更嚴重。所以C++標準庫中的智慧指標很好的解決了這些問題。

auto_ptr以物件的方式管理堆分配的記憶體,並在適當的時間(比如析構),釋放記憶體。我們只需要將new操作返回的指標作為auto_ptr的初始值,而不需要呼叫delete:

但是auto_ptr在拷貝時會返回一個左值並且不能呼叫delete[];所以在C++11中改用shared_ptr(允許多個指標指向一個物件),unique_ptr(“獨佔”所指向的物件)還有weak_ptr它是一種不控制所指物件生存期的智慧指標,指向shared_ptr所管理的對像,在memory標頭檔案中。

如下程式碼:

當然我們也可以shared_ptr和new來結合使用,但是必須使用直接初始化的形式來初始化一個智慧指標,

但是最好不要混合使用普通指標和智慧指標,最安全的分配和使用動態記憶體的方法是呼叫make_shared的標準庫函式。在使用它的時候,必須指定想要建立的物件型別。

如果我們不傳遞任何引數,物件會進行值初始化

shared_ptr 實現了引用計數型的智慧指標,當進行拷貝的時候,計數器都會遞增。而對一個物件進行賦值時,賦值操作符減少左運算元所指物件的引用計數(減1,如果引用計數為減至0,則刪除物件),並增加右運算元所指物件的引用計數(加1),如下程式碼:

此時r的引用技術為0,r原指物件被自動釋放。q的引用計數增加。

weak_ptr的使用和析構都不會改變shared_ptr的引用計數。weak_ptr可以使用一個非常重要的成員函式lock()從被觀測的shared_ptr獲得一個可用的shared_ptr物件, 從而操作資源。但當expired()==true的時候,lock()函式將返回一個儲存空指標的shared_ptr.如下:

當我們定義一個unique_ptr的時候,需要將其繫結到一個new返回的指標。

只能有一個uniqu_ptr指向物件,也就是說它不能被拷貝,也不支援賦值。但是我們可以通過move來移動

相關文章