C++表達式new與delete知識詳解
在C++中,new表達式用于動態(tài)創(chuàng)建對象,即在堆(自由存儲區(qū))空間上為對象分配內存,而程序員也要小心的使用這些申請來的內存空間,當不再使用時應該調用delete表達式來釋放該存儲空間并且將指針置零。 本文學習了如何動態(tài)創(chuàng)建對象,動態(tài)創(chuàng)建的對象與一般對象的區(qū)別,動態(tài)創(chuàng)建的對象的初始化以及釋放動態(tài)分配的內存等知識點。
C++中分配的內存大致有三類:靜態(tài)存儲區(qū),棧內存和堆內存
其中,靜態(tài)存儲區(qū)是在程序編譯階段就已經(jīng)分配好的,用于全局變量,static變量等;堆棧是比較常用的對象存儲方式。
new和delete是C++中程序員申請和撤銷堆內存的唯一方式(據(jù)我所知)。
1. 創(chuàng)建對象
無論是定義內置類型變量還是類類型變量,都必須指定其對應的數(shù)據(jù)類型和名字。
動態(tài)創(chuàng)建對象只需指定其數(shù)據(jù)類型,而不必為該對象命名。
也就是說,變量定義得到的對象可以通過額外定義的指針或其對象名本身來訪問,而動態(tài)創(chuàng)建方式得到的對象只能通過返回的指針來訪問,因為該對象并沒有名字。
2. 初始化
a. 可以在變量定義或是動態(tài)創(chuàng)建的階段初始化對象,例如:
int i(222); // definition, initialized int *pi = new int(222) // dynamically, initialized
b. 在這還要說一說變量定義時的默認初始化問題:
內置類型的變量初始化與其定義位置有關:函數(shù)外的自動初始化為零,而函數(shù)內的沒有初始化。對于類類型的變量,程序總是會調用默認構造函數(shù)來初始化,這個默認構造函數(shù)可以是系統(tǒng)自動生成的,也可以是程序員定義的。如果沒有默認構造函數(shù),那么該類型變量的定義也就不能采用默認初始化方式,必須提供顯式的初始化式。
動態(tài)創(chuàng)建的對象默認初始化與函數(shù)內變量定義的初始化方式相同,例如:
string *ps = new string; // initialized to empty string int *pi = new int; // pi points to an uninitialized int
c. 動態(tài)創(chuàng)建對象的值初始化(value-initialize)
這種值初始化不能用于變量定義,而只能用于動態(tài)創(chuàng)建方式。
string *ps2 = new string(); // initialized to empty string int *pi = new int(); // pi points to an int value-initialized to 0
值初始化表明程序員想要做初始化,但并未提供特定的初值。實際上,對于提供了默認構造函數(shù)的類類型(如string),沒有必要對其對象進行值初始化:無論程序是明確地不初始化還是要求進行值初始化,都會自動調用其默認構造函數(shù)初始化該對象。值初始化真正有用的是對于內置類型。另外需要注意的一點是,值初始化的 () 語法必須置于類型名后面,而不是變量名后面,否則得到的是一個函數(shù)聲明,如下:
int myValue(); // not value-initialized int variable, but a function named myValue int *myPtr = new int(); // correct! a value-initialized int object
對于沒有默認構造函數(shù)的類類型,無論是變量定義還是動態(tài)創(chuàng)建對象都必須采用顯式初始化。
3. 撤銷對象
動態(tài)創(chuàng)建的對象用完后,程序員必須顯式地將該對象占用的內存返還給自由存儲區(qū)。C++提供了delete表達式釋放指針所指向的地址空間。
delete myPtr;
上述語句釋放 myPtr 指向的 int 型對象所占用的內存。
C++沒有明確定義如何釋放指向不是用 new 分配的內存地址的指針。此外,編譯器通常不能斷定一個指針究竟指向什么類型的對象,因此如果調用delete 企圖釋放指向棧內存地址的指針時,編譯器并不會報錯,但請盡量不要依賴于該未定義的行為。
在C++中 delete 一個零值指針是合法且安全的,但實際上毫無意義。
懸垂指針(dangling pointer)
刪除了指針所指向的對象后,該指針變成懸垂指針。懸垂指針指向曾經(jīng)存放對象的內存,但該對象實際已經(jīng)不存在了。懸垂指針往往導致程序錯誤,并且很難檢測。因此,在調用delete 釋放指針所指對象內存后應該立刻將指針置零。
4. Const 對象的動態(tài)分配和回收
const 對象,必須在定義階段或動態(tài)創(chuàng)建階段進行初始化,并且初始化之后其值不能再修改。
與其他 const 對象的地址一樣,由于 new 返回的地址上存放的是 const 對象,因此該地址只能賦給指向 const 的指針。
// allocate and initialize a const object const int *pci = new const int(222); // initialize to 222 const int *pci2 = new const int(); // initialize to 0
盡管程序員不能改變 const 對象的值,但可撤銷對象本身。
delete pci; // ok: delete a const object
三種常見的程序錯誤都與動態(tài)內存分配相關:
1、刪除動態(tài)分配內存失敗,稱為內存泄漏(memory leak)
2、讀寫已刪除的對象
3、對同一個內存空間使用兩次 delete 表達式。當兩個指針指向同一個動態(tài)創(chuàng)建的對象,刪除時就會發(fā)生錯誤。第二個指針的 delete 操作往往會破壞自由存儲區(qū)。
個人實踐部分:
#include <iostream> #include <cstring> using namespace std; int main(void) { string str = "hello str"; // strNew points to dynamically allocated, // initialized to empty string string *strNew = new string; cout<<"str object address: "<<&str<<endl; cout<<"strNew pointer itself address: "<<&strNew<<endl; cout<<"strNew pointer to address: "<<strNew<<endl; // assignment *strNew = "hello strNew"; cout<<"strNew pointer to address: "<<strNew<<endl; // free memory delete strNew; cout<<"strNew pointer to address: "<<strNew<<endl; strNew = NULL; // point to other object strNew = &str; cout<<"strNew pointer to address: "<<strNew<<endl; const int cvalue(10); // iptr points to a const int object const int *iptr = new const int(222); cout<<"iptr value: "<<*iptr<<endl; delete iptr; iptr = NULL; iptr = &cvalue; cout<<"iptr value: "<<*iptr<<endl; return 0; }
一次運行的結果如下:
str object address: 0x28ff24 strNew pointer itself address: 0x28ff20 strNew pointer to address: 0x602f70 strNew pointer to address: 0x602f70 strNew pointer to address: 0x602f70 strNew pointer to address: 0x28ff24 iptr value: 222 iptr value: 10
程序中間將原來指向 new 創(chuàng)建的對象的指針重定向到一般的變量,可以看到指針存放地址的改變。另外需要注意,在釋放 new 對象之前不要將指針重新指向某個其他對象,這樣會導致原來動態(tài)創(chuàng)建的對象沒有指針指向它,無法釋放內存空間。
以上就是本文的全部內容,希望對大家的學習有所幫助。
欄 目:C語言
下一篇:詳解C++中的vector容器及用迭代器訪問vector的方法
本文標題:C++表達式new與delete知識詳解
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/2308.html
您可能感興趣的文章
- 04-02c語言的正則匹配函數(shù) c語言正則表達式函數(shù)庫
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對數(shù)怎么表達
- 04-02c語言沒有round函數(shù) round c語言
- 01-10數(shù)據(jù)結構課程設計-用棧實現(xiàn)表達式求值的方法詳解
- 01-10深入理解C++中常見的關鍵字含義
- 01-10使用C++實現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實現(xiàn)與遞歸實現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)


閱讀排行
本欄相關
- 04-02c語言函數(shù)調用后清空內存 c語言調用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調用函數(shù)求fibo C語言調用函數(shù)求
隨機閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結