c++中的空間主要分為三類,堆記憶體、棧記憶體和靜態記憶體,其中靜態記憶體用來儲存全域性物件(定義在任何函式之外的物件)、區域性static物件、類static資料成員,棧記憶體用於儲存定義在函式之內的非static物件。靜態記憶體和棧記憶體中的物件,所占用的空間都是由編譯器自動的建立和銷毀的。而除此之外,還有一種記憶體,是由我們來動態分配的,它就是堆記憶體。堆記憶體中的物件由我們手動創造,並且需要我們手動delete,如果忘記delete就會造成記憶體洩漏的情況。
下面的例子是在侯捷老師的c++課程中所舉的,在這裡我還是通過這個例子來說明記憶體的分配。我們建立兩個類,分別是complex和string,他們的定義如下。
class
complex
;private
:int ri=
0,vi=0;
}class
string
else}~
string()
;private
:char
* my_data;
}
這裡主要為了說明原理,先不對拷貝構造、拷貝賦值和析構函式進行宣告。
當我們在函式中動態分配一段記憶體給我們的物件時。
int
main()
分配動態陣列和單個物件的區別主要有以下幾個部分,對於動態陣列,用new typename [n]進行動態空間分配,刪除時也要配合delete ,這是一定要牢記在心的。那為什麼要這麼做呢?這是因為在**new [n]時分配了至少n個大小為類大小的空間給象,delete在告訴編譯器我們要刪除的是多個空間,而不是乙個。而delete和delete**在釋放記憶體的步驟是沒有什麼區別的,都是將物件所指的堆記憶體進行釋放,區別就是在第一步,delete呼叫一次析構函式,而delete呼叫n次析構函式。
當我們用delete和delete處理指向complex類物件的指標時,其實是沒有什麼區別的,因為int型別的數沒有析構函式,所以還是成功的釋放了記憶體。但是對於string類就不一樣了,如果我們使用delete,那麼只呼叫了一次析構函式,剩下的沒有呼叫析構函式,下面給出string類的析構函式。
string::
~string()
在析構函式中我們delete了s_data指標,對它所指的記憶體進行了釋放。
所以如果我們使用delete sm而不是delete sm,那麼在整個過程中只呼叫了一次析構函式,剩下9個s_data指標所指向的堆記憶體都沒有正確的進行釋放,這裡借用一下侯老師的圖,更方便理解。
所以說錯誤使用delete和delete並不是delete的指標記憶體沒有進行釋放,而是指標所指空間內的指向其他堆記憶體的指標沒有正確的釋放。
在聽完侯老師的課之後,我又自己瞎想了一下,寫了下面的一段**。
using
namespace std;
class
node};
class
s node* n;};
intmain()
/*result=
dxdx
dxdx
dxdx
dxdx
dxdx
1*/
在我的認知中,最後一段**應該出問題,因為我將n指向了乙個區域性變數,但是最後的結果卻是如上圖所示。經過在網上查詢資料,我按照自己的理解來解釋一下整個過程。
編譯器會如何處理這段**s* ps = new s[10]**語句呢,首先編譯器在堆記憶體中給分配了儲存10個s類物件的空間,再轉化為s的指標型別,賦值給ps,最後呼叫10次s的建構函式,此時建構函式是被壓入棧中,上面的fnode都是在棧中建立的,當fnode離開了這個建構函式的作用域後,就直接呼叫它的析構函式。
為什麼析構函式明明被呼叫了但是我們仍然能通過n訪問到i呢?
此時我們的n指向的是棧記憶體中的一段空間,打個比方說,你通過n獲得了棧記憶體中的一段空間,此時n就是你的鑰匙,空間就是你的房子,在你重新訪問之前,編譯器可以對你所指的空間進行覆蓋,它可以把這個房子裡面所有的家具都換掉,但是如果它沒有覆蓋這段空間,你就可以重新非法的進入這個房子,而這個房子裡面的家具跟你出去的時候還是一樣的。c++完全可以把你用過的棧空間全部清零,但是沒有必要這樣做,因為這樣做會花費額外的時間。
c++允許你這樣做,但這並不意味著這樣做是對的,這種未定義的行為是所有行為中最為危險的。
2、stackoverflow
棧 堆和靜態區 記憶體的講解
對於程式設計師,一般來說,我們可以簡單的理解為記憶體分為三個部分 靜態區,棧,堆。很多書沒有把把堆和棧解釋清楚,導致初學者總是分不清楚。其實堆疊就是棧,而不是 堆。堆的英文是heap 棧的英文是stack,也翻譯為堆疊。堆和棧都有自己的特性,這裡先不做討論。再打個比方 一層教學樓,可能有外語教室,允...
堆記憶體 棧記憶體 靜態儲存區
參考部落格 一般說到記憶體,指的是計算機的隨機儲存器ram,程式都是在這裡面執行。1.棧記憶體 棧記憶體由作業系統自動分配和釋放,速度快,使用方便,但程式設計師無法控制。若分配失敗,則提示棧溢位錯誤。注意,const區域性變數也儲存在棧中,向著記憶體位址減小的方向增長。棧記憶體儲存的是程式執行過程中...
堆記憶體 棧記憶體
從堆和棧的功能和作用來通俗的比較,堆主要用來存放物件的,棧主要是用來執行程式的.而這種不同又主要是由於堆和棧的特點決定的 在程式設計中,例如c c 中,所有的方法呼叫都是通過棧來進行的,所有的區域性變數,形式引數都是從棧中分配記憶體空間的。實際上也不是什麼分配,只是從棧頂向上用就行,就好像工廠中的傳...