operator new,new operator,placement new的区别
原文地址:http://www.cnblogs.com/jamesmile/archive/2010/04/17/1714311.html,在此感謝
C++中的operator new與new operator,看上去挺像的兩姐妹,卻有天壤之別。
重載的 operator new 必須是類成員函數或全局函數,而不可以是某一名空間
之內的函數或是全局靜態函數。此外,還要多加注意的是,重載 operator new 時需要兼容默
認的 operator new 的錯誤處理方式,并且要滿足 C++ 的標準規定 :當要求的內存大小為 0
byte 時也應該返回有效的內存地址。
?
?
如果使用不同的參數類型重載 operator new/delete,則請采用如下函數聲明形式:
// 返回的指針必須能被普通的 ::operator delete(void*) 釋放
void* operator new(size_t size, const char* file, int line);
// 析構函數拋異常時被調用
void operator delete(void* p, const char* file, int line);
調用時采用以下方式:
string* pStr = new (__FILE, __LINE__) string;
這樣就能跟蹤內存分配的具體位置,定位這個動作發生在哪個文件的哪一行代碼中了。
在“檢測內存錯誤”和“統計內存使用數據”時通常會用這種方式重載。
?
?
operator new
(1) 只分配所要求的空間,不調用相關對象的構造函數。當無法滿足所要求分配的空間時,則
??????? ->如果有new_handler,則調用new_handler,否則
??????? ->如果沒要求不拋出異常(以nothrow參數表達),則執行bad_alloc異常,否則
??????? ->返回0
(2) 可以被重載
(3) 重載時,返回類型必須聲明為void*
(4) 重載時,第一個參數類型必須為表達要求分配空間的大小(字節),類型為size_t
(5) 重載時,可以帶其它參數
new operator
(1) 調用operator new分配足夠的空間,并調用相關對象的構造函數
(2) 不可以被重載
相應地,operator delete與delete operator有相似的特性。
舉個例子
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,它將調用類X中的operator new,為該類的對象分配空間,然后調用當前實例的構造函數。
delete px;
該行代碼中的delete為delete operator,它將調用該實例的析構函數,然后調用類X中的operator delete,以釋放該實例占用的空間。
new operator與delete operator的行為是不能夠也不應該被改變,這是C++標準作出的承諾。而operator new與operator delete和C語言中的malloc與free對應,只負責分配及釋放空間。但使用operator new分配的空間必須使用operator delete來釋放,而不能使用free,因為它們對內存使用的登記方式不同。反過來亦是一樣。
你可以重載operator new和operator delete以實現對內存管理的不同要求,但你不能重載new operator或delete operator以改變它們的行為。
當重載operator new時,可以提供更多的參數,在new一個對象時,通過在關鍵字new后的括號傳遞額外的參數。比如以下的類
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();
新標準的C++允許以這樣的方式傳遞一個名為nothrow的參數,以表明當為該對象分配空間失敗時,不拋出異常,而是返回0,以兼容舊標準new的行為。比如
class B {};
B* pb = new (nothrow) B();
當然這只能對那些使用默認operator new操作符的類。對已經重載了operator new的類(比如上面的X和A),如果不聲明能接受nothrow參數,自然無法享受C++標準帶來的禮物。
?
operator new的六種重載形式
當寫出
p = new P();
這樣的代碼的時候, 實際上有兩步操作, 首先分配內存,
然后在分配好的內存之上初始化類成員.
第二步是有構造函數完成的, 第一步就是new函數的工作.
全局的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();??? //內存分配失敗不會拋出異常
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函數的一種重載形式.
如果A這個對象以同樣實行重載了new函數的化, 作為成員函數
會被優先調用.
C++的各種new簡介
1.new T
第一種new最簡單,調用類的(如果重載了的話)或者全局的operator new分配空間,然后用
類型后面列的參數來調用構造函數,用法是
new TypeName(initial_args_list). 如果沒有參數,括號一般可以省略.例如
int *p=new int;
int *p=new int(10);
int *p=new foo("hello");
通過調用delete來銷毀:
delete p;
2. new T[]
這種new用來創建一個動態的對象數組,他會調用對象的operator new[]來分配內存(如果
沒有則調用operator new,搜索順序同上),然后調用對象的默認構造函數初始化每個對象
用法:
new TypeName[num_of_objects];
例如
int *p= new int[10];
銷毀時使用operator delete[]
3.new()T 和new() T[]
這是個帶參數的new,這種形式的new會調用operator new(size_t,OtherType)來分配內存
這里的OtherType要和new括號里的參數的類型兼容,
這種語法通常用來在某個特定的地址構件對象,稱為placement new,前提是operator new
(size_t,void*)已經定義,通常編譯器已經提供了一個實現,包含<new>頭文件即可,這個
實現只是簡單的把參數的指定的地址返回,因而new()運算符就會在括號里的地址上創建
對象
需要說明的是,第二個參數不是一定要是void*,可以識別的合法類型,這時候由C++的重載
機制來決定調用那個operator new
當然,我們可以提供自己的operator new(size_,Type),來決定new的行為,比如
char data[1000][sizeof(foo)];
inline void* operator new(size_t ,int n)
{
??????? return data[n];
}
就可以使用這樣有趣的語法來創建對象:
foo *p=new(6) foo(); //把對象創建在data的第六個單元上
的確很有意思
標準庫還提供了一個nothrow的實現:
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
就可以實現調用new失敗時不拋出異常
new(nothrow) int(10);
// nothrow 是std::nothrow_t的一個實例
placement new 創建的對象不能直接delete來銷毀,而是要調用對象的析夠函數來銷毀對
象,至于對象所占的內存如何處理,要看這塊內存的具體來源
4. operator new(size_t)
這個的運算符分配參數指定大小的內存并返回首地址,可以為自定義的類重載這個運算符,
方法就是在類里面聲明加上
void *operator new(size_t size)
{
??????? //在這里分配內存并返回其地址
}
無論是否聲明,類里面重載的各種operator new和operator delete都是具有static屬性的
一般不需要直接調用operator new,除非直接分配原始內存(這一點類似于C的malloc)
在沖突的情況下要調用全局的operator加上::作用域運算符:
::operator new(1000); // 分配1000個字節
返回的內存需要回收的話,調用對應的operator delete
5.operator new[](size_t)
這個也是分配內存,,只不過是專門針對數組,也就是new T[]這種形式,當然,需要時可以
顯式調用
6.operator new(size_t size, OtherType other_value)
和operator new[](size_t size, OtherType other_value)
參見上面的new()
需要強調的是,new用來創建對象并分配內存,它的行為是不可改變的,可以改變的是各種
operator new,我們就可以通過重載operator new來實現我們的內存分配方案.
?
?--------------------------------------------
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 }在調用前面的兩個冒號很關鍵,是為了避免進行無限遞歸(沒有它函數將一直調用自己下去)。
關于"::"的小插曲:
?
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
是否調用構造函數/析構函數
使用new操作符來分配對象內存時會經歷三個步驟:
- 第一步:調用operator new 函數(對于數組是operator new[])分配一塊足夠大的,原始的,未命名的內存空間以便存儲特定類型的對象。
- 第二步:編譯器運行相應的構造函數以構造對象,并為其傳入初值。
- 第三部:對象構造完成后,返回一個指向該對象的指針。
使用delete操作符來釋放對象內存時會經歷兩個步驟:
- 第一步:調用對象的析構函數。
- 第二步:編譯器調用operator delete(或operator delete[])函數釋放內存空間。
總之來說,new/delete會調用對象的構造函數/析構函數以完成對象的構造/析構。而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處設置斷點,觀看ptr所指內存的內容:
可以看出A的默認構造函數并沒有被調用,因為數據成員a,b的值并沒有得到初始化,這也是上面我為什么說使用malloc/free來處理C++的自定義類型不合適,其實不止自定義類型,標準庫中凡是需要構造/析構的類型通通不合適。
而使用new來分配對象時:
int main() { A * ptr = new A; }查看程序生成的匯編代碼可以發現,A的默認構造函數被調用了:
from this article
?
--------------------------------------------
有關于三者的區別
?
轉載于:https://www.cnblogs.com/guxuanqing/p/4802064.html
總結
以上是生活随笔為你收集整理的operator new,new operator,placement new的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [CODEVS1258]关路灯
- 下一篇: UI-- Empty Applicati