周全解析C++中的new,operator new與placement new。本站提示廣大學習愛好者:(周全解析C++中的new,operator new與placement new)文章只能為提供參考,不一定能成為您想要的結果。以下是周全解析C++中的new,operator new與placement new正文
new operator/delete operator就是new和delete操作符,而operator new/operator delete是函數。
new operator
(1)挪用operator new分派足夠的空間,並挪用相干對象的結構函數
(2)弗成以被重載
operator new
(1)只分派所請求的空間,不挪用相干對象的結構函數。當沒法知足所請求分派的空間時,則
->假如有new_handler,則挪用new_handler,不然
->假如沒請求不拋出異常(以nothrow參數表達),則履行bad_alloc異常,不然
->前往0
(2)可以被重載
(3)重載時,前往類型必需聲明為void*
(4)重載時,第一個參數類型必需為表達請求分派空間的年夜小(字節),類型為size_t
(5)重載時,可以帶其它參數
delete 與 delete operator相似。
#include<iostream>
#include<string>
using namespace std;
class X
{
public:
X() {cout<<"constructor of X"<<endl;}
~X() {cout<<"destructor of X"<<endl;}
void* operator new(size_t size,string str)
{
cout<<"operator new size"<<size<<"with string"<<str<<endl;
return ::operator new(size);
}
void operator delete(void* pointee)
{
cout<<"operator delete"<<endl;
::operator delete(pointee);
}
private:
int num;
}
int main()
{
X *px=new("A new class") X;
delete px;
return 0;
}
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和operator delete?
謎底平日是:為了效力。缺省的operator new和operator delete具有異常好的通用性,它的這類靈巧性也使得在某些特定的場所下,可以進一步改良它的機能。特別在那些須要靜態分派年夜量的但很小的對象的運用法式裡,情形更是如斯。詳細可參考《Effective C++》中的第二章內存治理。
Placement new的寄義
placement new 是重載operator new 的一個尺度、全局的版本,它不克不及夠被自界說的版本取代(不像通俗版本的operator new和operator delete可以或許被調換)。
void *operator new( size_t, void * p ) throw() { return p; }
placement new的履行疏忽了size_t參數,只返還第二個參數。其成果是許可用戶把一個對象放到一個特定的處所,到達挪用結構函數的後果。和其他通俗的new分歧的是,它在括號裡多了別的一個參數。好比:
Widget * p = new Widget; //ordinary new
pi = new (ptr) int; pi = new (ptr) int; //placement new
括號裡的參數ptr是一個指針,它指向一個內存緩沖器,placement new將在這個緩沖器上分派一個對象。Placement new的前往值是這個被結構對象的地址(好比括號中的傳遞參數)。placement new重要實用於:在對時光請求異常高的運用法式中,由於這些法式分派的時光是肯定的;長時光運轉而不被打斷的法式;和履行一個渣滓搜集器 (garbage collector)。
new 、operator new 和 placement new 差別
(1)new :不克不及被重載,其行動老是分歧的。它先挪用operator new分派內存,然後挪用結構函數初始化那段內存。
new 操作符的履行進程:
1. 挪用operator new分派內存 ;
2. 挪用結構函數生成類對象;
3. 前往響應指針。
(2)operator new:要完成分歧的內存分派行動,應當重載operator new,而不是new。
operator new就像operator + 一樣,是可以重載的。假如類中沒有重載operator new,那末挪用的就是全局的::operator new來完成堆的分派。同理,operator new[]、operator delete、operator delete[]也是可以重載的。
(3)placement new:只是operator new重載的一個版本。它其實不分派內存,只是前往指向曾經分派好的某段內存的一個指針。是以不克不及刪除它,但須要挪用對象的析構函數。
假如你想在曾經分派的內存中創立一個對象,應用new時行欠亨的。也就是說placement new許可你在一個曾經分派好的內存中(棧或許堆中)結構一個新的對象。原型中void* p現實上就是指向一個曾經分派好的內存緩沖區的的首地址。
Placement new 存在的來由
1.用placement new 處理buffer的成績
成績描寫:用new分派的數組緩沖時,因為挪用了默許結構函數,是以履行效力上欠安。若沒有默許結構函數則會產生編譯時毛病。假如你想在預分派的內存上創立對象,用缺省的new操作符是行欠亨的。要處理這個成績,你可以用placement new結構。它許可你結構一個新對象到預分派的內存上。
2.增年夜時空效力的成績
應用new操作符分派內存須要在堆中查找足夠年夜的殘剩空間,明顯這個操作速度是很慢的,並且有能夠湧現沒法分派內存的異常(空間不敷)。placement new便可以處理這個成績。我們結構對象都是在一個事後預備好了的內存緩沖區中停止,不須要查找內存,內存分派的時光是常數;並且不會湧現在法式運轉半途湧現內存缺乏的異常。所以,placement new異常合適那些對時光請求比擬高,長時光運轉不願望被打斷的運用法式。
Placement new應用步調
在許多情形下,placement new的應用辦法和其他通俗的new有所分歧。這裡供給了它的應用步調。
第一步 緩存提早分派
有三種方法:
1.為了包管經由過程placement new應用的緩存區的memory alignment(內存隊列)准確預備,應用通俗的new來分派它:在堆長進行分派
class Task ;
char * buff = new [sizeof(Task)]; //分派內存
(請留意auto或許static內存並不是都准確地為每個對象類型分列,所以,你將不克不及以placement new應用它們。)
2.在棧長進行分派
class Task ;
char buf[N*sizeof(Task)]; //分派內存
3.還有一種方法,就是直接經由過程地址來應用。(必需是成心義的地址)
void* buf = reinterpret_cast<void*> (0xF00F);
第二步:對象的分派
在適才已分派的緩存區挪用placement new來結構一個對象。
Task *ptask = new (buf) Task
第三步:應用
依照通俗方法應用分派的對象:
ptask->memberfunction();
ptask-> member;
//...
第四步:對象的析構
一旦你應用完這個對象,你必需挪用它的析構函數來撲滅它。依照上面的方法挪用析構函數:
ptask->~Task(); //挪用內在的析構函數
第五步:釋放
你可以重復應用緩存並給它分派一個新的對象(反復步調2,3,4)假如你不盤算再次應用這個緩存,你可以象如許釋放它:delete [] buf;
跳過任何步調便可能招致運轉時光的瓦解,內存洩漏,和其它的意想不到的情形。假如你確切須要應用placement new,請賣力遵守以上的步調。
#include <iostream>
using namespace std;
class X
{
public:
X() { cout<<"constructor of X"<<endl; }
~X() { cout<<"destructor of X"<<endl;}
void SetNum(int n)
{
num = n;
}
int GetNum()
{
return num;
}
private:
int num;
};
int main()
{
char* buf = new char[sizeof(X)];
X *px = new(buf) X;
px->SetNum(10);
cout<<px->GetNum()<<endl;
px->~X();
delete []buf;
return 0;
}