operator new,new operator,placement new的区别
原文地址:http://www.cnblogs.com/jamesmile/archive/2010/04/17/1714311.html,在此感謝
C++中的operator new與new operator,看上去挺像的兩姐妹,卻有天壤之別。
重載的 operator new 必須是類成員函數(shù)或全局函數(shù),而不可以是某一名空間
之內(nèi)的函數(shù)或是全局靜態(tài)函數(shù)。此外,還要多加注意的是,重載 operator new 時(shí)需要兼容默
認(rèn)的 operator new 的錯(cuò)誤處理方式,并且要滿足 C++ 的標(biāo)準(zhǔn)規(guī)定 :當(dāng)要求的內(nèi)存大小為 0
byte 時(shí)也應(yīng)該返回有效的內(nèi)存地址。
?
?
如果使用不同的參數(shù)類型重載 operator new/delete,則請采用如下函數(shù)聲明形式:
// 返回的指針必須能被普通的 ::operator delete(void*) 釋放
void* operator new(size_t size, const char* file, int line);
// 析構(gòu)函數(shù)拋異常時(shí)被調(diào)用
void operator delete(void* p, const char* file, int line);
調(diào)用時(shí)采用以下方式:
string* pStr = new (__FILE, __LINE__) string;
這樣就能跟蹤內(nèi)存分配的具體位置,定位這個(gè)動作發(fā)生在哪個(gè)文件的哪一行代碼中了。
在“檢測內(nèi)存錯(cuò)誤”和“統(tǒng)計(jì)內(nèi)存使用數(shù)據(jù)”時(shí)通常會用這種方式重載。
?
?
operator new
(1) 只分配所要求的空間,不調(diào)用相關(guān)對象的構(gòu)造函數(shù)。當(dāng)無法滿足所要求分配的空間時(shí),則
??????? ->如果有new_handler,則調(diào)用new_handler,否則
??????? ->如果沒要求不拋出異常(以nothrow參數(shù)表達(dá)),則執(zhí)行bad_alloc異常,否則
??????? ->返回0
(2) 可以被重載
(3) 重載時(shí),返回類型必須聲明為void*
(4) 重載時(shí),第一個(gè)參數(shù)類型必須為表達(dá)要求分配空間的大小(字節(jié)),類型為size_t
(5) 重載時(shí),可以帶其它參數(shù)
new operator
(1) 調(diào)用operator new分配足夠的空間,并調(diào)用相關(guān)對象的構(gòu)造函數(shù)
(2) 不可以被重載
相應(yīng)地,operator delete與delete operator有相似的特性。
舉個(gè)例子
class X?
{
public:
…………
??? static void* operator new(size_t size)
{
??? return ::operator new(size);
}
static void operator delete(void* pointee)
{
??? ::operator delete(pointee);
}
…………
};
X* px = new X();
該行代碼中的new為new operator,它將調(diào)用類X中的operator new,為該類的對象分配空間,然后調(diào)用當(dāng)前實(shí)例的構(gòu)造函數(shù)。
delete px;
該行代碼中的delete為delete operator,它將調(diào)用該實(shí)例的析構(gòu)函數(shù),然后調(diào)用類X中的operator delete,以釋放該實(shí)例占用的空間。
new operator與delete operator的行為是不能夠也不應(yīng)該被改變,這是C++標(biāo)準(zhǔn)作出的承諾。而operator new與operator delete和C語言中的malloc與free對應(yīng),只負(fù)責(zé)分配及釋放空間。但使用operator new分配的空間必須使用operator delete來釋放,而不能使用free,因?yàn)樗鼈儗?nèi)存使用的登記方式不同。反過來亦是一樣。
你可以重載operator new和operator delete以實(shí)現(xiàn)對內(nèi)存管理的不同要求,但你不能重載new operator或delete operator以改變它們的行為。
當(dāng)重載operator new時(shí),可以提供更多的參數(shù),在new一個(gè)對象時(shí),通過在關(guān)鍵字new后的括號傳遞額外的參數(shù)。比如以下的類
class A?
{
public:
??? …………
??? static void* operator new(size_t size, const string& example)
{
??? cout << example << endl;
??? return ::operator new(size);
}
…………
};
A* pa = new (“This will be printed out in operator new”) A();
新標(biāo)準(zhǔn)的C++允許以這樣的方式傳遞一個(gè)名為nothrow的參數(shù),以表明當(dāng)為該對象分配空間失敗時(shí),不拋出異常,而是返回0,以兼容舊標(biāo)準(zhǔn)new的行為。比如
class B {};
B* pb = new (nothrow) B();
當(dāng)然這只能對那些使用默認(rèn)operator new操作符的類。對已經(jīng)重載了operator new的類(比如上面的X和A),如果不聲明能接受nothrow參數(shù),自然無法享受C++標(biāo)準(zhǔn)帶來的禮物。
?
operator new的六種重載形式
當(dāng)寫出
p = new P();
這樣的代碼的時(shí)候, 實(shí)際上有兩步操作, 首先分配內(nèi)存,
然后在分配好的內(nèi)存之上初始化類成員.
第二步是有構(gòu)造函數(shù)完成的, 第一步就是new函數(shù)的工作.
全局的new有六種重載形式,?
void *operator new(std::size_t count)
??? throw(std::bad_alloc);???????????? //一般的版本
void *operator new(std::size_t count,? //兼容早版本的new
??? const std::nothrow_t&) throw();??? //內(nèi)存分配失敗不會拋出異常
void *operator new(std::size_t count, void *ptr) throw();
?????????????????????????????????????? //placement版本
void *operator new[](std::size_t count)? //
??? throw(std::bad_alloc);
void *operator new[](std::size_t count,? //
??? const std::nothrow_t&) throw();
void *operator new[](std::size_t count, void *ptr) throw();
所以, 剛才的用法, 就是使用new函數(shù)的一種重載形式.
如果A這個(gè)對象以同樣實(shí)行重載了new函數(shù)的化, 作為成員函數(shù)
會被優(yōu)先調(diào)用.
C++的各種new簡介
1.new T
第一種new最簡單,調(diào)用類的(如果重載了的話)或者全局的operator new分配空間,然后用
類型后面列的參數(shù)來調(diào)用構(gòu)造函數(shù),用法是
new TypeName(initial_args_list). 如果沒有參數(shù),括號一般可以省略.例如
int *p=new int;
int *p=new int(10);
int *p=new foo("hello");
通過調(diào)用delete來銷毀:
delete p;
2. new T[]
這種new用來創(chuàng)建一個(gè)動態(tài)的對象數(shù)組,他會調(diào)用對象的operator new[]來分配內(nèi)存(如果
沒有則調(diào)用operator new,搜索順序同上),然后調(diào)用對象的默認(rèn)構(gòu)造函數(shù)初始化每個(gè)對象
用法:
new TypeName[num_of_objects];
例如
int *p= new int[10];
銷毀時(shí)使用operator delete[]
3.new()T 和new() T[]
這是個(gè)帶參數(shù)的new,這種形式的new會調(diào)用operator new(size_t,OtherType)來分配內(nèi)存
這里的OtherType要和new括號里的參數(shù)的類型兼容,
這種語法通常用來在某個(gè)特定的地址構(gòu)件對象,稱為placement new,前提是operator new
(size_t,void*)已經(jīng)定義,通常編譯器已經(jīng)提供了一個(gè)實(shí)現(xiàn),包含<new>頭文件即可,這個(gè)
實(shí)現(xiàn)只是簡單的把參數(shù)的指定的地址返回,因而new()運(yùn)算符就會在括號里的地址上創(chuàng)建
對象
需要說明的是,第二個(gè)參數(shù)不是一定要是void*,可以識別的合法類型,這時(shí)候由C++的重載
機(jī)制來決定調(diào)用那個(gè)operator new
當(dāng)然,我們可以提供自己的operator new(size_,Type),來決定new的行為,比如
char data[1000][sizeof(foo)];
inline void* operator new(size_t ,int n)
{
??????? return data[n];
}
就可以使用這樣有趣的語法來創(chuàng)建對象:
foo *p=new(6) foo(); //把對象創(chuàng)建在data的第六個(gè)單元上
的確很有意思
標(biāo)準(zhǔn)庫還提供了一個(gè)nothrow的實(shí)現(xiàn):
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
就可以實(shí)現(xiàn)調(diào)用new失敗時(shí)不拋出異常
new(nothrow) int(10);
// nothrow 是std::nothrow_t的一個(gè)實(shí)例
placement new 創(chuàng)建的對象不能直接delete來銷毀,而是要調(diào)用對象的析夠函數(shù)來銷毀對
象,至于對象所占的內(nèi)存如何處理,要看這塊內(nèi)存的具體來源
4. operator new(size_t)
這個(gè)的運(yùn)算符分配參數(shù)指定大小的內(nèi)存并返回首地址,可以為自定義的類重載這個(gè)運(yùn)算符,
方法就是在類里面聲明加上
void *operator new(size_t size)
{
??????? //在這里分配內(nèi)存并返回其地址
}
無論是否聲明,類里面重載的各種operator new和operator delete都是具有static屬性的
一般不需要直接調(diào)用operator new,除非直接分配原始內(nèi)存(這一點(diǎn)類似于C的malloc)
在沖突的情況下要調(diào)用全局的operator加上::作用域運(yùn)算符:
::operator new(1000); // 分配1000個(gè)字節(jié)
返回的內(nèi)存需要回收的話,調(diào)用對應(yīng)的operator delete
5.operator new[](size_t)
這個(gè)也是分配內(nèi)存,,只不過是專門針對數(shù)組,也就是new T[]這種形式,當(dāng)然,需要時(shí)可以
顯式調(diào)用
6.operator new(size_t size, OtherType other_value)
和operator new[](size_t size, OtherType other_value)
參見上面的new()
需要強(qiáng)調(diào)的是,new用來創(chuàng)建對象并分配內(nèi)存,它的行為是不可改變的,可以改變的是各種
operator new,我們就可以通過重載operator new來實(shí)現(xiàn)我們的內(nèi)存分配方案.
?
?--------------------------------------------
1 #include <iostream> 2 #include <string> 3 #include <crtdbg.h> 4 using namespace std; 5 6 class X 7 { 8 public: 9 X(){cout<<"constructor of X"<<endl;} 10 ~X(){cout<<"deconstructor of X"<<endl;} 11 12 void* operator new(size_t size,string str) 13 { 14 cout<<"operator new size:"<<size<<" with string:"<<str<<endl; 15 return ::operator new(size); 16 } 17 18 void operator delete(void *point) 19 { 20 cout<<"operator delete"<<endl; operator delete(point); 21 //::operator delete(point); 22 } 23 24 private: 25 int num; 26 }; 27 int main(){ 28 X *px = new("A new class") X; 29 delete px; 30 cout<<sizeof("A new class")<<endl; 31 string strd="A new class"; 32 int len = sizeof("A new class"); 33 for (int i = 0;i<len;i++) 34 { 35 cout<<strd[i]; 36 } 37 cout<<"END"; 38 return 0; 39 }在調(diào)用前面的兩個(gè)冒號很關(guān)鍵,是為了避免進(jìn)行無限遞歸(沒有它函數(shù)將一直調(diào)用自己下去)。
關(guān)于"::"的小插曲:
?
1 #include <iostream> 2 using namespace std; 3 int n = 12;// A global variable 4 int main() 5 { 6 int n = 13;// A local variable 7 cout << ::n << endl;// Print the global variable: 12 8 cout << n << endl;// Print the local variable: 13 9 }?
?
?2019-03-06
是否調(diào)用構(gòu)造函數(shù)/析構(gòu)函數(shù)
使用new操作符來分配對象內(nèi)存時(shí)會經(jīng)歷三個(gè)步驟:
- 第一步:調(diào)用operator new 函數(shù)(對于數(shù)組是operator new[])分配一塊足夠大的,原始的,未命名的內(nèi)存空間以便存儲特定類型的對象。
- 第二步:編譯器運(yùn)行相應(yīng)的構(gòu)造函數(shù)以構(gòu)造對象,并為其傳入初值。
- 第三部:對象構(gòu)造完成后,返回一個(gè)指向該對象的指針。
使用delete操作符來釋放對象內(nèi)存時(shí)會經(jīng)歷兩個(gè)步驟:
- 第一步:調(diào)用對象的析構(gòu)函數(shù)。
- 第二步:編譯器調(diào)用operator delete(或operator delete[])函數(shù)釋放內(nèi)存空間。
總之來說,new/delete會調(diào)用對象的構(gòu)造函數(shù)/析構(gòu)函數(shù)以完成對象的構(gòu)造/析構(gòu)。而malloc則不會。如果你不嫌啰嗦可以看下我的例子:
class A { public: A() :a(1), b(1.11){} private: int a; double b; }; int main() { A * ptr = (A*)malloc(sizeof(A)); return 0; }在return處設(shè)置斷點(diǎn),觀看ptr所指內(nèi)存的內(nèi)容:
可以看出A的默認(rèn)構(gòu)造函數(shù)并沒有被調(diào)用,因?yàn)閿?shù)據(jù)成員a,b的值并沒有得到初始化,這也是上面我為什么說使用malloc/free來處理C++的自定義類型不合適,其實(shí)不止自定義類型,標(biāo)準(zhǔn)庫中凡是需要構(gòu)造/析構(gòu)的類型通通不合適。
而使用new來分配對象時(shí):
int main() { A * ptr = new A; }查看程序生成的匯編代碼可以發(fā)現(xiàn),A的默認(rèn)構(gòu)造函數(shù)被調(diào)用了:
from this article
?
--------------------------------------------
有關(guān)于三者的區(qū)別
?
轉(zhuǎn)載于:https://www.cnblogs.com/guxuanqing/p/4802064.html
總結(jié)
以上是生活随笔為你收集整理的operator new,new operator,placement new的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [CODEVS1258]关路灯
- 下一篇: UI-- Empty Applicati