天天看點

C++類和new、delete操作符和堆和棧記憶體的配置設定

如果你是Java、C#、PHP程式員,那麼會對 new 非常熟悉,在這些程式設計語言中,隻能通過 new 來建立對象。

在C++中,你可以像定義變量一樣來建立對象,如:

<code>Student stu; //對象已被執行個體化,已配置設定記憶體空間,可以使用了 stu.say(); //調用成員函數</code>

這種情況下,系統會在棧區為對象配置設定記憶體。棧區是記憶體中的一塊區域,由系統自動配置設定和釋放,程式員無法操控,一般用來存放函數的參數值、局部變量、局部對象等。

當發生函數調用時,系統将函數參數、局部變量、局部對象依次壓入棧區;函數執行結束,再按照先進後出的原則将它們彈出(銷毀)。

對于大部分程式,這不會有什麼問題。但當你希望在函數調用結束前銷毀對象時,你是無能為力的。或者你希望通過 for 循環來建立多個對象,這種方法同樣也做不到。

這個時候 new 和 delete 就派上了用場:使用 new 建立的對象,可以在任意時刻通過 delete 銷毀,而且隻需要一個指針指向它。

以前面的 Student 類為例,可以這樣來動态建立對象:

也可以使用構造函數:

這樣,就在堆區為對象配置設定了記憶體,并調用了構造函數。

但是此時程式員還無法通路這個對象,因為這個對象既沒有名字,也沒有指針指向它。這種對象稱為

匿名對象

,它确實存在,但無法通路。

用一個指針來指向Student類的對象:

或者:

當不再需要對象時,可以通過 delete 銷毀:

這樣,就釋放掉了對象占用的記憶體,并調用了析構函數。

需要說明的是:new 在堆區為對象配置設定記憶體。與棧區不同的是,堆區記憶體由程式員配置設定和釋放,系統不會自動銷毀,即使函數調用結束了,仍然會保留堆區記憶體。如果程式員不主動回收堆區記憶體,那麼隻能在程式運作結束後由作業系統回收。

為了避免記憶體洩露,強烈建議 new 和 delete 成對出現,及時銷毀不再需要的對象。

例如,下面的代碼會造成嚴重的記憶體洩露:

<code>#include &lt;iostream&gt; #include &lt;cstdlib&gt; using namespace std; class Demo{ private: double n; double m; int i; }; void func(){ Demo *p = new Demo; } int main(){ int i; for(i=1; i&lt;=1000000; i++){ func(); } system("pause"); return 0; }</code>

當程式運作到 system("pause"); 語句時,你可以打開任務管理器,會發現這個小小的程式竟然占用了 32M 記憶體。

這是因為每次調用 func 函數,都會建立一個對象,并用 p 指向它。函數運作結束,僅僅釋放了指針變量 p 占用的記憶體,而沒有釋放 p 所指向的對象占用的記憶體。

如果在 func 函數中不回收對象記憶體,那麼你将永遠無法回收,隻能等到程式運作結束由作業系統回收,這就是典型的記憶體洩露。

另外注意,C語言中的 malloc、free 函數不能用來為對象配置設定和釋放記憶體。請看下面的例子:

<code>#include &lt;iostream&gt; using namespace std; class Demo{ public: Demo(); ~Demo(); }; Demo::Demo(){ cout&lt;&lt;"Constructor"&lt;&lt;endl; } Demo::~Demo(){ cout&lt;&lt;"Destructor"&lt;&lt;endl; } int main(){ cout&lt;&lt;"------new------"&lt;&lt;endl; Demo *p1 = new Demo; //建立一個對象 Demo *p2 = new Demo[5]; //建立一組對象 cout&lt;&lt;"------malloc------"&lt;&lt;endl&lt;&lt;endl; Demo *p3 = (Demo*)malloc(sizeof(Demo)); cout&lt;&lt;"------delete------"&lt;&lt;endl; delete p1; //銷毀一個對象 delete[] p2; //銷毀一組對象 cout&lt;&lt;"------free------"&lt;&lt;endl; free(p3); return 0; }</code>

運作結果:

------new------

Constructor

------malloc------

------delete------

Destructor

------free------

從程式運作結果可以看出:malloc 雖然配置設定了記憶體,但沒有調用構造函數;free 雖然釋放了記憶體,但也沒有調用析構函數。

繼續閱讀