“瑜珈山夜話” ----記憶體分配(二)
阿新 • • 發佈:2019-02-08
在理解這個問題之前,我們先看一下下面的這段程式,有這麼一個程式段:
class A
{
public:
A() { cout<<"A is here!"<<endl; }
~A(){ cout<<"A is dead!"<<endl; }
private:
int i;
};
A* pA=new A;
delete pA;
在這個簡單的程式段裡面,new/delete究竟做了些什麼?
實際上,這段程式裡面隱含呼叫了一些我們沒有看到的東西,那就是:
static void* operator new(size_t sz);
static void operator delete(void* p);
值得注意的是,這兩個函式都是static的,所以如果我們過載了這2個函式(我們要麼不過載,要過載就要2個一起行動),也應該宣告為static的,如果我們沒有宣告,系統也會為我們自動加上。另外,這是兩個記憶體分配原語,要麼成功,要麼沒有分配任何記憶體。
size_t是什麼東西呢?我在第一次看到這個動動的時候也是十分的困惑,畢竟以前沒有見過。size_t在<cstddef>中定義,是一種無符號整數型別(不一定是int),用來儲存物件的大小,這一用法是從C語言中借用過來的,現在你應該明白了吧(我學習的時候可是鬱悶了好幾天,沒有人可以問,因為不知道有個csdn:)
new A;實際上做了2件事:呼叫opeator new,在自由儲存區分配一個sizeof(A)大小的記憶體空間;然後呼叫建構函式A(),在這塊記憶體空間上類磚砌瓦,建造起我們的物件。同樣對於delete,則做了相反的兩件事:呼叫解構函式~A(),銷燬物件,呼叫operator delete,釋放記憶體。不過需要注意的是,new分配一塊記憶體的時候,並沒有對這塊記憶體空間做清零等任何動作,只是拿了過來,這塊記憶體上放的仍然是原來的資料(垃圾資料),delete的時候,也只是釋放這塊記憶體,歸還給作業系統,上面的資料還在上面,所以delete pA之後,pA的值沒變,他指向的那塊記憶體的值也沒有變,不過似乎有什麼問題,我們看一下下面的這個程式段:
int *p=new int(50000);
cout<<*p<<" "<<p<<endl;
delete p;
cout<<*p<<" "<<p<<endl;
我們可以清楚地看到,指標p存放的資料仍然是原來的地址,但是*p的內容卻發生了變化,在我的機器上(win2000, VC6)始終是-572662307,不清楚這是為什麼,難道系統做了什麼手腳?還望高手指教 。
在這裡我們可以看到,new的工作實際上就是保證相互分離的儲存分配和初始化工作能夠很好的在一起工作,不過這裡可能讓初學者迷惑的是,我們定義了一個帶有引數的new,但是我們用的時候卻沒有顯式的去呼叫,而是讓系統“神祕”的去提供這個引數。是的,這樣做毫無疑問增加了複雜性,但是讓基類獲取了為一集派生類提供分配和釋放服務的能力。
class A
{
public:
A() { cout<<"A is here!"<<endl; }
~A(){ cout<<"A is dead!"<<endl; }
private:
int i;
};
A* pA=new A;
delete pA;
在這個簡單的程式段裡面,new/delete究竟做了些什麼?
實際上,這段程式裡面隱含呼叫了一些我們沒有看到的東西,那就是:
static void* operator new(size_t sz);
static void operator delete(void* p);
值得注意的是,這兩個函式都是static的,所以如果我們過載了這2個函式(我們要麼不過載,要過載就要2個一起行動),也應該宣告為static的,如果我們沒有宣告,系統也會為我們自動加上。另外,這是兩個記憶體分配原語,要麼成功,要麼沒有分配任何記憶體。
size_t是什麼東西呢?我在第一次看到這個動動的時候也是十分的困惑,畢竟以前沒有見過。size_t在<cstddef>中定義,是一種無符號整數型別(不一定是int),用來儲存物件的大小,這一用法是從C語言中借用過來的,現在你應該明白了吧(我學習的時候可是鬱悶了好幾天,沒有人可以問,因為不知道有個csdn:)
new A;實際上做了2件事:呼叫opeator new,在自由儲存區分配一個sizeof(A)大小的記憶體空間;然後呼叫建構函式A(),在這塊記憶體空間上類磚砌瓦,建造起我們的物件。同樣對於delete,則做了相反的兩件事:呼叫解構函式~A(),銷燬物件,呼叫operator delete,釋放記憶體。不過需要注意的是,new分配一塊記憶體的時候,並沒有對這塊記憶體空間做清零等任何動作,只是拿了過來,這塊記憶體上放的仍然是原來的資料(垃圾資料),delete的時候,也只是釋放這塊記憶體,歸還給作業系統,上面的資料還在上面,所以delete pA之後,pA的值沒變,他指向的那塊記憶體的值也沒有變,不過似乎有什麼問題,我們看一下下面的這個程式段:
int *p=new int(50000);
cout<<*p<<" "<<p<<endl;
delete p;
cout<<*p<<" "<<p<<endl;
我們可以清楚地看到,指標p存放的資料仍然是原來的地址,但是*p的內容卻發生了變化,在我的機器上(win2000, VC6)始終是-572662307,不清楚這是為什麼,難道系統做了什麼手腳?還望高手指教
在這裡我們可以看到,new的工作實際上就是保證相互分離的儲存分配和初始化工作能夠很好的在一起工作,不過這裡可能讓初學者迷惑的是,我們定義了一個帶有引數的new,但是我們用的時候卻沒有顯式的去呼叫,而是讓系統“神祕”的去提供這個引數。是的,這樣做毫無疑問增加了複雜性,但是讓基類獲取了為一集派生類提供分配和釋放服務的能力。