C++中new的用法及說明
C++ new的用法
知識點小結(jié)
new其實就是告訴計算機開辟一段新的空間,但是和一般的聲明不同的是,new開辟的空間在堆上,而一般聲明的變量存放在棧上。
通常來說,當(dāng)在局部函數(shù)中new出一段新的空間,該段空間在局部函數(shù)調(diào)用結(jié)束后仍然能夠使用,可以用來向主函數(shù)傳遞參數(shù)。
另外需要注意的是,new的使用格式,new出來的是一段空間的首地址。所以一般需要用指針來存放這段地址。
具體的代碼如下:
#include <iostream> using namespace std; int example1() { //可以在new后面直接賦值 int *p = new int(3); //也可以單獨賦值 //*p = 3; //如果不想使用指針,可以定義一個變量,在new之前用“*”表示new出來的內(nèi)容 int q = *new int; q = 1; cout << q << endl; return *p; } int* example2() { //當(dāng)new一個數(shù)組時,同樣用一個指針接住數(shù)組的首地址 int *q = new int[3]; for(int i=0; i<3; i++) q[i] = i; return q; } struct student { string name; int score; }; student* example3() { //這里是用一個結(jié)構(gòu)體指針接住結(jié)構(gòu)體數(shù)組的首地址 //對于結(jié)構(gòu)體指針,個人認為目前這種賦值方法比較方便 student *stlist = new student[3]{{"abc", 90}, {"bac", 78}, {"ccd", 93}}; return stlist; } int main() { int e1 = example1(); cout <<"e1: "<< e1 << endl; int *e2 = example2(); for(int i=0; i<3; i++) cout << e2[i] << " "; cout << endl; student *st1 = example3(); for(int i=0; i<3; i++) cout << st1[i].name << " " << st1[i].score << endl; return 0; }
new的三種使用方法
概念
在C++中new的三種用法包括:plain new, nothrow new 和 placement new。
plain new 就是我們最常使用的new的方式,在C++中的定義如下:
1 void* operator new(std::size_t) throw(std::bad_alloc); ? 2 void operator delete( void *) throw();
plain new在分配失敗的情況下,拋出異常std::bad_alloc而不是返回NULL,因此通過判斷返回值是否為NULL是徒勞的。
nothrow new 是不拋出異常的運算符new的形式。nothrow new在失敗時,返回NULL。定義如下:
1 void * operator new(std::size_t, const std::nothrow_t&) throw(); 2 void operator delete(void*) throw();
placement new 意即“放置”,這種new允許在一塊已經(jīng)分配成功的內(nèi)存上重新構(gòu)造對象或?qū)ο髷?shù)組。placement new不用擔(dān)心內(nèi)存分配失敗,因為它根本不分配內(nèi)存,它做的唯一一件事情就是調(diào)用對象的構(gòu)造函數(shù)。定義如下:
1 void* operator new(size_t, void*); 2 void operator delete(void*, void*);
palcement new 的主要用途就是反復(fù)使用一塊較大的動態(tài)分配的內(nèi)存來構(gòu)造不同類型的對象或者他們的數(shù)組。placement new構(gòu)造起來的對象或其數(shù)組,要顯示的調(diào)用他們的析構(gòu)函數(shù)來銷毀,千萬不要使用delete。
示例
- plain new
char *getMemory(unsigned long size) ?? { ? ? ? ? char * p = new char[size]; ?? ? ? return p;? } ?? void main(void) ?? { ? ? try{ ?? ? ? ? ? char * p = getMemory(1000000); ? ?// 可能發(fā)生異常 ? ? ? ? // ... ?? ? ? ? ? delete [] p; ?? ? ? } ?? ? ? catch(const std::bad_alloc & ex) ?? ? ? { ? ? ? ? cout << ex.what(); ? ? } ?? }
- nowthrow new
void func(unsinged long length) ?? { ? ? unsinged char * p = new(nothrow) unsinged char[length]; ?? ? ? // 在使用這種new時要加(nothrow) ,明示不使用異常處理 。 ? ? ? if (p == NULL) ?// 因不拋異常,故定要檢查 ? ? ? ? cout << "allocte failed !"; ?? ? ? ? ? // ... ?? ? ? delete [] p; }
- placement new
void main() ?? { ? ? ? using namespace std; ?? ? ? char * p = new(nothrow) char [4]; ?? ? ? if (p == NULL) ?? ? ? { ? ? ? ? cout << "allocte failed" << endl; ? ? ? ? ? exit( -1 ); ? ? } ?? ? ? // ... ?? ? ? long * q = new (p) long(1000); ?? ? ? delete []p; ? ?// 只釋放 p,不要用q釋放。 }
p和q僅僅是首址相同,所構(gòu)建的對象可以類型不同。所“放置”的空間應(yīng)小于原空間,以防不測。當(dāng)”放置new”超過了申請的范圍,Debug版下會掛機,但Release版竟然能運行而不出錯!
該運算符的作用是:只要第一次分配成功,不再擔(dān)心分配失敗。
void main() ?? { ? ? using namespace std; ?? ? ? char * p = new(nothrow) char [100]; ?? ? ? if (p == NULL) ?? ? ? { ? ? ? ? ? cout << "allocte failed" << endl; ? ? ? ? exit(-1); ? ? } ?? ? ? long * q1 = new (p) long(100); ?? ? ? // 使用q1 ?... ?? ? ? int * q2 = new (p) int[100/sizeof(int)]; ?? ? ? // 使用q2 ... ?? ? ? ADT * q3 = new (p) ADT[100/sizeof(ADT)]; ?? ? ? // 使用q3 ?然后釋放對象 ... ?? ? ? delete [] p; ? ?// 只釋放空間,不再析構(gòu)對象。 }
注意:使用該運算符構(gòu)造的對象或數(shù)組,一定要顯式調(diào)用析構(gòu)函數(shù),不可用delete代替析構(gòu),因為placement new 的對象的大小不再與原空間相同。
void main() ?? { ? ? ? using namespace std; ?? ? ? char * p = new(nothrow) char [sizeof(ADT)+2]; ?? ? ? if (p == NULL) ?? ? ? { ? ? ? ? ? cout << "allocte failed" << endl; ? ? ? ? exit(-1);? ? ? }? ? ? // ...? ? ? ADT * q = new (p) ADT;? ? ? // ...? ? ? // delete q; // 錯誤 ? ? q->ADT::~ADT(); ?// 顯式調(diào)用析構(gòu)函數(shù),僅釋放對象 ? ? delete [] p; ? ? // 最后,再用原指針來釋放內(nèi)存 }
placement new 的主要用途就是可以反復(fù)使用一塊已申請成功的內(nèi)存空間。這樣可以避免申請失敗的徒勞,又可以避免使用后的釋放。
特別要注意的是對于 placement new 絕不可以調(diào)用的delete, 因為該new只是使用別人替它申請的地方(只是個租房戶,不是房主。無權(quán)將房子賣掉)。釋放內(nèi)存是nothrow new的事,即要使用原來的指針釋放內(nèi)存。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺談C++函數(shù)聲明后面加throw()的作用(必看)
下面小編就為大家?guī)硪黄獪\談C++函數(shù)聲明后面加throw()的作用(必看)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01C++常用函數(shù)之XML JSON格式轉(zhuǎn)換問題
XML在Json出現(xiàn)前應(yīng)用很廣泛,靈活性好,應(yīng)用語言也沒有限制,發(fā)展了這么長時間后xml標準已經(jīng)很臃腫。這篇文章主要介紹了C++常用函數(shù)之XML JSON格式轉(zhuǎn)換問題,需要的朋友可以參考下2020-02-02C語言數(shù)據(jù)結(jié)構(gòu)與算法之單鏈表
單鏈表是一種鏈式存取的數(shù)據(jù)結(jié)構(gòu),用一組地址任意的存儲單元存放線性表中的數(shù)據(jù)元素。本文將為大家介紹C語言中單鏈表的基本概念與讀取數(shù)據(jù)元素,需要的可以參考一下2021-12-12