C++中new的3種形態:
new operator
operator new
placement new
new operator:
new操作符,像 + - * / && . :: ?: 等操作符一樣,是語言內置的, 它不能被重載,不能改變其行為。
它的行為包括分配內存的 operator new 和調用構造函數的 placement new。
new operator 實際上做了三件事:獲得一塊內存空間、調用構造函數、返回正確的指針。如果創建的是簡單類型(如char)的變量,那么第二步會被省略。
比如:
CTest* pT = new CTest(2, 2);
它的調用實際上等效于:
void* p = operator new( sizeof(CTest) );//operator new分配內存
CTest* pT = new(p) CTest(2, 2);//placement new調用構造函數,并返回正確的CTest*指針
operator new:
原型為: void* operator new(size_t size);
它分配指定大小的內存, 可以被重載, 可以添加額外的參數, 但第一個參數必須為 size_t 。
它除了被 new operator 調用外也可以直接被調用, 如:
void* p = operator new(sizeof(CTest));
這種用法和調用 malloc 一樣, 只分配了sizeof(CTest)大小的內存.
placement new:
置換new,它在一塊已經指定的內存上調用構造函數, 包含頭文件<new>之后也可以直接使用,
如:
CTest* pT = new(p) CTest(2, 2);
它在p這塊內存上調用CTest的構造函數來初始化CTest。
這個函數返回一個對象指針,對象是在傳遞進來的p這塊內存上分配的,也就說指定一個額外的自變量(p)作為new operator "隱式調用operator new"時所用,
于是被調用的operator new 除了接受"一定得有的size_t"這個自變量外,還需要接受一個void *的指針,指向一塊內存,準備用來接受構造函數好的對象,這樣operator new就
是所謂的placement new,其operator new定義如下:
void * operator new(size_t,void *location){
return loaction;
}
所以operator new的目的就是為對象找到一塊內存,然后返回一個指針指向它.在placement new的情況下,調用者已經知道指向內存的指針,因為調用者知道對象應該放哪,
因此placement new唯一需要做的就是將它獲得的指針再返回,至于沒有用到(但一定得有的)size_t參數,所以不賦予名稱,以免編譯器發出"某物未被使用"的警告。
如果用 placement new 構造出來的對象,必須顯示的調用對象的析構函數,
如:
pT->~CTest();
然后釋放內存存, 調用 operator delete (對應于分配時的 operator new)operator delete(pT);
小結:
1)、想在堆上建立一個對象,應該用 new 操作符,它既分配內存又為對象調用構
造函數。
2)、如果僅僅想分配內存,就應該調用 operator new 函數;它不會調用構造函數。
3)、如果想定制在堆對象被建立時的內存分配過程,應該重載 operator new 函數,
然后使用 new operator,new operator 會調用定制的 operator new 。
4)、如果想在一塊已經獲得指針的內存里建立一個對象,應該用 placement new 。
placement new 主要適用于:
(a): 對時間要求非常高的應用程序中,因為這些程序分配的時間是確定的;
(b): 長時間運行而不被打斷的程序;
(c): 以及執行一個垃圾收集器 (garbage collector) 。
注意:如果用 placement new 構造出來的對象,必須顯示的調用對象的析構函數。
程序示例:
1 #include <iostream>
2 using namespace std;
3 #include <new>
4
5
6 class CTest{
7 public:
8 CTest(int _x, int _y){
9 X = _x;
10 Y = _y;
11 }
12 ~CTest(){
13 X = 0;
14 Y = 0;
15 }
16 void Test(char* sz){
17 cout<<sz<<":"<<" "<<"X="<<X<<" "<<"Y="<<Y<<endl;
18 }
19 int X;
20 int Y;
21 };
22
23 //new operator:
24 void F1(){
25 CTest* pT = new CTest(1, 1); // new operator
26
27 pT->Test("F1");
28
29 delete pT;
30
31 }
32
33
34 // operator new
35 // placement new
36
37 void F2(){
38 void* p = operator new(sizeof(CTest)); // operator new : 分配內存
39 CTest* pT = new(p) CTest(2, 2); // placement new: 構造對象
40
41 pT->Test("F2");
42
43 pT->~CTest(); // 必須顯示析構對象
44 operator delete(pT); // operator delete: 釋放內存
45 }
46
47
48 // 也可這樣實現:
49 void F3(){
50 char* p = new char[sizeof(CTest)]; // new operator: char為內置類型,不會調用構造函數,相當于只分配內存
51
52 CTest* pT = new(p) CTest(3, 3); // placement new: 在這塊內存上構造CTest對象
53
54 pT->Test("F3");
55
56 pT->~CTest(); // 必須顯示析構CTest對象
57
58 delete [] p; // delete operator: char為內置類型,不會調用析構函數,相當于只釋放內存
59 }
60
61
62 void main(){
63 F1();
64 F2();
65 F3();
66 }
F1: X=1 Y=1
F2: X=2 Y=2
F3: X=3 Y=3
Press any key to continue
C++中的delete:
為了避免resource leaks,每一個動態分配行為都應該必須匹配一個相應但相反的釋放動作;
如果你寫:
string *ps;
delete ps;//使用delete operator;相對與 new operator
指向delete ps;要求編譯器既能夠析構ps所指的對象,又能夠釋放被該對象占用的內存,
其中釋放內存是由operator delete所執行的(相對于 operator new),其聲明如下:
void operator delete(void *memoryTOBeDeallocated);
因此執行delete ps; 那么編譯器就產生了如下代碼:
ps->~string(); //調用對象的析構函數dtoroperator
operator delete(ps); //釋放對象所占的內存
這里呈現的一個暗示就是:若果你打算處理原始的、未設置初值的內存,應該完全回避new operator和delete operator ,改調用operator new 取得內存,operator delete歸還系統內存
void *buffer=operator new(50*sizeif(char)); // 分配內存相當于C語言中的malloc
operator delete(buffer); //釋放內存 但沒用調用任何析構函數 相當于C語言中的free
如果你使用了placement new在某塊內存上產生對象,你應該避免對那塊內存使用delete operator,這是因為delete operator會調用operator delete來釋放內存,但是該內存內含的對象最初并非是由operator new分配的,畢竟placement new只返回它所接受的指針而已,但不知道這個指針是從哪里來的,所以為了抵消該對象的構造函數的影響,你應該直接調用該對象的析構函數
class Widget{
public:
Widget(int WidgetSize);


};
Widget* constructWidgetInBUuffer(void *buffer,int WidgetSize){
return new(buffer) Widget(WidgetSize);
}
//以下函數用來分配及釋放shared memory中的內存
void *mallocShared(size_t size);
void freeShared(void *memory);
void *sharedMemory=mallocShared(sizeof(Widget));
Widget *pw=constructWidgetInBUuffer(sharedMemory,10);//運用placement new


delete pw;//無定義??!,因為sharedMemory來自mallocShared,不是來自operator new
pw->~Widget();//OK!!析構pw所指的Widget對象,但未釋放Widget對象的內存
freeShared(pw);//OK!! 釋放pw所指的內存 不用調用任何析構函數