1. 程式人生 > >C++類和new、delete操作符和堆和棧記憶體的分配

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

如果你是Java、C#、PHP程式設計師,那麼會對 new 非常熟悉,在這些程式語言中,只能通過 new 來建立物件。
在C++中,你可以像定義變數一樣來建立物件,如:
  1. Studentstu; //物件已被例項化,已分配記憶體空間,可以使用了
  2. stu.say(); //呼叫成員函式
這種情況下,系統會在棧區為物件分配記憶體。棧區是記憶體中的一塊區域,由系統自動分配和釋放,程式設計師無法操控,一般用來存放函式的引數值、區域性變數、區域性物件等。

當發生函式呼叫時,系統將函式引數、區域性變數、區域性物件依次壓入棧區;函式執行結束,再按照先進後出的原則將它們彈出(銷燬)。

對於大部分程式,這不會有什麼問題。但當你希望在函式呼叫結束前銷燬物件時,你是無能為力的。或者你希望通過 for 迴圈來建立多個物件,這種方法同樣也做不到。


這個時候 new 和 delete 就派上了用場:使用 new 建立的物件,可以在任意時刻通過 delete 銷燬,而且只需要一個指標指向它。

以前面的 Student 類為例,可以這樣來動態建立物件:
new Student;
也可以使用建構函式:
new Student("小明", 15, 90.5f);
這樣,就在堆區為物件分配了記憶體,並呼叫了建構函式。

但是此時程式設計師還無法訪問這個物件,因為這個物件既沒有名字,也沒有指標指向它。這種物件稱為匿名物件,它確實存在,但無法訪問。

用一個指標來指向Student類的物件:
Student *pStu;
pStu = new Student("小明", 15, 90.5f);
或者:
Student *pStu = new Student("小明", 15, 90.5f);

當不再需要物件時,可以通過 delete 銷燬:
delete pStu;
這樣,就釋放掉了物件佔用的記憶體,並呼叫了解構函式。

需要說明的是:new 在堆區為物件分配記憶體。與棧區不同的是,堆區記憶體由程式設計師分配和釋放,系統不會自動銷燬,即使函式呼叫結束了,仍然會保留堆區記憶體。如果程式設計師不主動回收堆區記憶體,那麼只能在程式執行結束後由作業系統回收。

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

例如,下面的程式碼會造成嚴重的記憶體洩露:
  1. #include
    <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. classDemo{
  5. private:
  6. double n;
  7. double m;
  8. int i;
  9. };
  10. void func(){
  11. Demo*p = new Demo;
  12. }
  13. int main(){
  14. int i;
  15. for(i=1; i<=1000000; i++){
  16. func();
  17. }
  18. system("pause");
  19. return 0;
  20. }
當程式執行到 system("pause"); 語句時,你可以開啟工作管理員,會發現這個小小的程式竟然佔用了 32M 記憶體。

這是因為每次呼叫 func 函式,都會建立一個物件,並用 p 指向它。函式執行結束,僅僅釋放了指標變數 p 佔用的記憶體,而沒有釋放 p 所指向的物件佔用的記憶體。

如果在 func 函式中不回收物件記憶體,那麼你將永遠無法回收,只能等到程式執行結束由作業系統回收,這就是典型的記憶體洩露。

另外注意,C語言中的 malloc、free 函式不能用來為物件分配和釋放記憶體。請看下面的例子:
  1. #include <iostream>
  2. using namespace std;
  3. classDemo{
  4. public:
  5. Demo();
  6. ~Demo();
  7. };
  8. Demo::Demo(){
  9. cout<<"Constructor"<<endl;
  10. }
  11. Demo::~Demo(){
  12. cout<<"Destructor"<<endl;
  13. }
  14. int main(){
  15. cout<<"------new------"<<endl;
  16. Demo*p1 = new Demo; //建立一個物件
  17. Demo*p2 = new Demo[5]; //建立一組物件
  18. cout<<"------malloc------"<<endl<<endl;
  19. Demo*p3 = (Demo*)malloc(sizeof(Demo));
  20. cout<<"------delete------"<<endl;
  21. delete p1; //銷燬一個物件
  22. delete[] p2; //銷燬一組物件
  23. cout<<"------free------"<<endl;
  24. free(p3);
  25. return 0;
  26. }
執行結果:
------new------
Constructor
Constructor
Constructor
Constructor
Constructor
Constructor
------malloc------

------delete------
Destructor
Destructor
Destructor
Destructor
Destructor
Destructor
------free------

從程式執行結果可以看出:malloc 雖然分配了記憶體,但沒有呼叫建構函式;free 雖然釋放了記憶體,但也沒有呼叫解構函式。

相關推薦

C++newdelete操作符記憶體分配

如果你是Java、C#、PHP程式設計師,那麼會對 new 非常熟悉,在這些程式語言中,只能通過 new 來建立物件。 在C++中,你可以像定義變數一樣來建立物件,如: Studentstu; //物件已被例項化,已分配記憶體空間,可以使用了stu.say();

C++運算符newdelete

C++在軟件開發中過程中,常常需要動態地分配和撤銷內存空間,例如對動態鏈表中結點的插入與刪除。 new int; //開辟一個存放整數的存儲空間,返回一個指向該存儲空間的地址(即指針)。 new int(100); //指定該整數的初值為100 new char[10]; //包含10個字符的空間 new

2.16 C++newdelete操作符

運行 out 可能 clas cout std 存儲 分配 程序 參考: http://www.weixueyuan.net/view/6347.html 總結:    當我們需要為類對象動態分配存儲空間時,我們應該使用C++語言提供的new與new[]操作符,而不要使用C

C++——建立的時候用new與不用new 的區別(從的解讀)

轉自:https://www.cnblogs.com/tony-li/p/4111588.html C++在建立物件的時候可以採用兩種方式:(例如類名為Test) Test test  或者 Test* pTest = new Test()。         這兩

C++中重載重寫(覆蓋)隱藏的區別

post space csdn depend amp 不同類 sin ase 返回 轉載自:https://blog.csdn.net/zx3517288/article/details/48976097 基本概念: 重載:是指同一可訪問區內被聲明的幾個具有不同參數列(參數

Linux後臺進程管理以及ctrl+z(掛起)ctrl+c(中斷)ctrl+(退出)ctrl+d(EOF)的區別(轉)

列表 art 信息 csdn 而是 png detail tps 後臺 一、後臺進程管理命令 fg、bg、jobs、&、ctrl + z、ctrl + c、ctrl + \、ctrl + d1、 &加在一個命令的最後,可以把這個命令放到後臺執行 ,如fire

PHP設計模式:自動載入PSR-0規範鏈式操作11種面向物件設計模式實現使用OOP的基本原則自動載入配置

一、類自動載入      SPL函式 (standard php librarys)      類自動載入,儘管 __autoload() 函式也能自動載入類和介面,但更建議使用&nbs

C++之newdelete 與mallocfree

在C/C++程式設計中經常會申請記憶體,而對記憶體的申請釋放操作有兩套方法: new、delete 與malloc、free。 1. 區別 (1). new、delete是c++中的操作符,malloc、free是C中的一個函式,它們都可用於申請動態記憶體和釋放記憶體。 (2)

C語言的指標連結串列的原理各類操作

一、指標 1、運用指標         什麼是指標?什麼是記憶體地址?什麼叫做指標的取值?指標是一個儲存計算機記憶體地址的變數。從指標指向的記憶體讀取資料稱作指標的取值。指標可以指向某些具體型別的變數地址,例如int、long和double。指標也可以

Java物件例項的關係Java資料封裝Java繼承多型Java抽象介面Java靜態欄位方法Java包作用域Java的classpathjarJava核心

Java物件和例項的關係: 面向物件程式設計(Object-Oriented Programming),是對現實世界建立計算機模型的一種方法。 class是物件的模板,它定義瞭如何建立例項,class的名字就是資料型別。一個class裡可以有多個欄位(field),欄位用

ORACLE觸發器newold特殊變數

:new --為一個引用最新的列值; :old --為一個引用以前的列值; 這兩個變數只有在使用了關鍵字 "FOR EACH ROW"時才存在.且update語句兩個都有,而insert只有:new ,delect 只有:old; 系統中的觸發器例項: create or replace trigger J

c++のstatic靜態成員物件的動態建立釋放

1、靜態成員變數 (1)核心思想 靜態成員變數的初始化必須在類的外部,也可以通過物件直接進行賦值; 靜態函式的只能使用靜態成員變數,不能使用其他普通的成員變數; (2)程式碼例子邊看邊講解 #include <stdio.h> cla

C++ 用new delete 動態建立刪除陣列

指標名直接作為引數傳遞給函式時{ int *p;  fun(p) },傳遞的是指標的值,不是指標的地址,所以被調函式無法修改傳入指標的值。如果要對實參p做賦值操作,有兩種方法,1,傳遞實參的地址 &pvoid fun(int **pp);int *p;fun(&

面試題:C++有了malloc/free,為什麼還需要newdelete

1、面試寶典面試題(P81):C++有了malloc/free,為什麼還需要new、delete? malloc與free是C、C++語言的標準庫函式,new/delete是C++的運算子。他們都用於申請動態記憶體和釋放記憶體。 對於非內部資料型別的物件而言,只用mall

Linux後臺程序管理以及ctrl+z(掛起)ctrl+c(中斷)ctrl+\(退出)ctrl+d(EOF)的區別

轉自:http://blog.csdn.net/fengyifei11228/article/details/5737371             http://idas643.blog.163.com/blog/static/1671048382013414938465

C ++的newdelete

當寫出p = new P();這樣的程式碼的時候, 實際上有兩步操作, 首先分配記憶體,然後在分配好的記憶體之上初始化類成員.第二步是有建構函式完成的, 第一步就是new函式的工作.全域性的new有六種過載形式,void *operator new(std::size_t

C++模板來展示newdelete操作符原理

C++中的new與delete可以認為是C中的malloc與free的升級版本。 new包含兩部分,一部分是與malloc功能相同,是從堆上面申請記憶體塊,第二部是呼叫類的構造方法來初始化剛申請的記憶體。 delete是new的逆過程,先呼叫類的析構方法來反初始化,再

C++的newdelete及其記憶體管理

程式碼寫多了,就麻木了。new和delete很好用,平時用的時候沒想太多。但如果“想太多”就會引發出很多東西。 new和delete跟sizeof一樣,是操作符,關鍵字,而不是函式。new和delete比malloc和free具有更強的功能。 new和delete用於動態

c++的拷貝賦值與銷毀(拷貝構造函數拷貝賦值運算符析構函數)

錯誤 保存 編譯 oid 生成 標準庫 int 為什麽 explicit 拷貝構造函數 如果一個構造函數的第一個參數是自身類類型的引用,且任何額外參數都有默認值,則此構造函數是拷貝構造函數。 拷貝構造函數第一個參數必須是一個引用類型。此參數幾乎總是一個con

Java的知識點6—— 強制型別轉換基本型別轉化時常見錯誤問題 簡單的鍵盤輸入輸出

 強制型別轉換 強制型別轉換,又被稱為造型,用於顯式的轉換一個數值的型別。在有可能丟失資訊的情況下進行的轉換是通過造型來完成的,但可能造成精度降低或溢位。 public class Test2 { public static void main(String [] ar