1. 程式人生 > >C++中new和delete

C++中new和delete

New運算子

1、new表示式:

當我們使用一條new表示式時:

string *sp=newstring(“a value”);

string *arr=newstring[10];

實際上執行了三步操作。第一步,new表示式呼叫一個名為operatornew(或者operatornew[])的標準庫函式。改函式分配一塊足夠大的、原始的、未命名的記憶體空間以便儲存特定型別的物件(或者物件陣列)。第二部,編譯器執行相應的建構函式以構造這些物件,併為其傳入初始值。第三部,物件被分配了空間並構造完成,返回一個指向該物件的指標。

       當我們使用一條delete表示式刪除一個動態分配的物件時:

       delete sp;

       delete []arr;

實際執行了兩步操作。第一步,對sp所指的物件或者arr所指的陣列中的元素執行對應的解構函式。第二部,編譯器呼叫名為operatordelete(或者operator[]delete)的標準庫函式釋放記憶體空間。

2、new運算子過載

       應用程式可以在全域性作用域中定義operator new函式和operatordelete函式,也可以將它們定義為成員函式。當編譯器發現一條new表示式或者delte表示式後,將在程式中查詢可供呼叫的operator函式。如果分配(釋放)的物件是類型別,則編譯器首先在類及其基類的作用域中查詢。此時如果該類含有operatornew成員或operatordelete成員,則相應的表示式將呼叫這些成員。否則,編譯器在全域性作用域中查詢匹配的函式。此時如果編譯器找到了使用者自定義的版本,則使用該版本執行new表示式或delete表示式;如果沒找到,則使用標準庫定義的版本。

       標準庫對每個new、new[]、delete、delete[]都有三個過載版本:

       如果要過載new和delete運算子,需要注意:

       (1)對於operator new函式或者operatornew[]函式來說,它的返回型別必須是void*,第一個形參的型別必須是size_t且該形參不能含有預設實參。

       (2)儘管一般情況下我們可以自定義具有任何形參的operatornew,但是下面這個函式卻無論如何都不能被使用者過載:

       void *operator new(size_t,void*);

       (3)當定義為類成員運算子過載時,它們是隱式靜態的,我們無需顯示宣告static,因為operatornew用在物件構造之前而operatordelete用在物件銷燬之後,所以這兩個(new和delete)必須是靜態的,而且不能操作任何非靜態資料成員。

例如:

#include<iostream>
using namespace std;
struct Test
{
public:
         Test(inta,double b):_value(a),d(b){}
    void *operator new(size_tn,int x)//new運算子過載
    {
        cout<<"Test::operatornew   "<<x<<endl;
                  Test *p=(Test*)malloc(sizeof(Test));
//                cout<<_value<<endl;//new過載運算子預設是static的,因此不能呼叫非靜態變數和函式
//                cout<<d<<endl;
        returnp;
    }
         void operator delete(void *p)
         {
                  if(p==nullptr)
                          return ;
                  cout<<"Test::operator delete       "<<endl;
cout<<c<<endl;
                  free(p);
         }
         ~Test(){cout<<"destruct function"<<endl;}
private:
         int_value;
         doubled;
         static int c;
};
int Test::c=30;
 
int main()
{                       
         Test *p=new(10)Test(1,3);//new表示式,呼叫new運算子過載函式
         deletep;
 
         system("pause");
         return0;
}

new表示式的用法:new [引數列表]TYPE [初始化列表],如上面構造p時的10就是在引數列表中,預設從第二個引數開始。其中兩個列表都是可選的,當省略前一個列表的時候,說明分配空間的new運算子只需要一個大小的引數;當省略了後面的列表時,說明TYPE存在一個沒有引數的建構函式。如果一個型別沒有可用的建構函式,那麼不能簡單的使用new來分配記憶體。

輸出結果如下:


3、帶位置的new運算子表示式

語法:new (expression-list ) new-type-id ( optional-initializer-expression-list );

例子:

#include<iostream>
#include<new>
using namespace std;
 
int main()
{                       
         intdata=100;
         int*ip=new(&data) int(10);//呼叫void* operator new(size_t,void*)函式
         cout<<*ip<<endl;
 
         int table[20]={1,2,3,4,5,6,7,8,9,0};
         int*itp=new(&table[3]) int[5]();//在棧上的記憶體也可以用於new分配,但不能delete
         cout<<table[3]<<endl;//輸出都為0,如果是int *itp=new(&table[3]) int[5];則table中儲存的數不變
         cout<<table[4]<<endl;
         cout<<table[5]<<endl;
         cout<<table[6]<<endl;
         cout<<table[7]<<endl;
 
         system("pause");
         return0;
}
 

輸出結果:


下面這個不是很正確,只是參考了其分類和用例

http://cpp.ezbty.org/content/science_doc/c:new運算子和new表示式詳解

《C++primer第5版》P726 19.1節:控制記憶體分配