New (C++)

new是C++程式設計語言中的一種語言結構，用於動態分配記憶體、並用建構函式初始化分配的記憶體。new的使用稱為“new運算子表示式”，其內部實現分為兩步：每個new獲取的物件，必須用delete析構並釋放記憶體，以免記憶體洩漏。new運算子表示式是C++的一種語言結構，不可過載。但使用者可過載operator new()函式。new運算子表示式語法.普通的new運算子表示式.new的語法是:p_var = new typename;其中codice_2是已經定義的型別為codice_3的指標變數。透過codice_4初始化物件，使用下述語法：p_var = new type(initializer); // 或者如此初始化 new type{initializer};其中codice_5是傳遞給建構函式的實參表或初值。動態生成物件陣列的new運算子表示式.codice_4也可建立一個物件陣列，稱之為“array forms new”：p_var = new type [size];C++98標準規定，codice_4建立的物件陣列不能被顯式初始化， 陣列所有元素被預設初始化。如果陣列基型別沒有預設初始化，則編譯報錯。但C++11已經允許顯式初始化，例如：int *p_int = new int[3] {1,2,3};如此生成的物件陣列，在釋放時必須呼叫codice_8表示式。例如 delete [] p_int ;帶位置的new運算子表示式.帶位置的new 的語法是：new ( expression-list ) new-type-id ( optional-initializer-expression-list );其中，expression-list將作為operator new()函式的實參列表的結尾部分。這種形式的new運算子表示式首先呼叫operator new(size_t,OtherTypeList)函式來獲取記憶體；然後對該物件執行建構函式。這裡的OtherTypeList作為形參列表要和new表示式中第一個括號裡的實參列表expression-list的型別相容。帶位置的new運算子，語義上包括四種使用情形，其中前兩種已經在標準標頭檔案中實現了：狹義上的帶位置的new是指第一種情形。使用這種placement new，原因之一是使用者的程式不能在一塊記憶體上自行呼叫其建構函式，必須由編譯系統生成的程式碼呼叫建構函式。原因之二是可能需要把物件放在特定硬體的記憶體地址上，或者放在多處理器核心的共享的記憶體地址上。釋放這種物件時，不能呼叫placement delete，應直接呼叫解構函式，如：codice_9然後再自行釋放記憶體。舉例：using namespace std;int main(int argc, char* argv[])char buf[100];int *p=new (buf) int(101);cout«*(int*)buf«endl;return 0;保證不丟擲異常的new運算子表示式.在分配記憶體失敗時，new運算子的標準行為是丟擲codice_1異常。也可以讓new運算子在分配記憶體失敗時不丟擲異常而是返回空指標。new (nothrow) Type ( optional-initializer-expression-list );或new (nothrow) Type[size];其中codice_11是codice_12的一個例項自行定製引數的new運算子表示式.new運算子的引數可以是任意合法型別的列表。由C++的過載機制來決定呼叫那個operator new。new (Type_list) Type ( optional-initializer-expression-list );或new (Type_list) Type[size];帶位置的delete運算子表示式.C++ 不能使用帶位置的 delete 運算子表示式直接析構一個物件但不釋放其記憶體。因此，對於用廣義的帶位置new表示式構建的物件，析構釋放時有兩種辦法：第一種辦法是直接寫一個函式，完成析構物件、釋放記憶體的操作：voiddestroy (T * p, A &amp; arena)p-&gt;~T() ; // First invoke the destructor explicitly.arena.deallocate(p) ; // Then call the deallocator function directly.如此使用：A arena ;T * p = new (arena) T ;destroy(p, arena) ;第二種辦法是分兩步顯式呼叫解構函式與帶位置的operator delete函式：A arena ;T * p = new (arena) T ;p-&gt;~T() ; // First invoke the destructor explicitly.operator delete(p, arena) ; // Then call the deallocator function indirectly via operator delete(void *, A &amp;) .帶位置的operator delete()函式，可以被帶位置的new算符表示式自動呼叫。這是在物件的建構函式丟擲異常的時候，用來釋放掉帶位置的operator new函式獲取的記憶體。以避免記憶體洩露。例如：char buf[100];struct A {} ;struct E {} ;class T {public:void * operator new(std::size_t,const A &amp;){std::cout « "Placement new called for class T." « std::endl;return buf;void operator delete(void*, const A &amp;)std::cout « "Placement delete called for class T." « std::endl;} ;void * operator new ( std::size_t, const A &amp; )void operator delete ( void *, const A &amp; )int main ()A a ;try {T * p = new (a) T ;/* do something */return 0 ;operator new()的函式過載.使用new動態生成一個物件，實際上是呼叫了new運算子表示式。該運算子首先呼叫了operator new函式動態分配記憶體，然後呼叫型別的建構函式初始化這塊記憶體。new運算子是不能被過載的，但是下述各種operator new()函式既可以作為全域性函式過載，也可以作為類成員函式或作用域內的函式過載，即由程式設計者指定如何獲取記憶體。普通的operator new(size_t size)函式.new運算子呼叫operator new函式動態分配記憶體。首先查詢類內是否有operator new函式可供使用。operator new函式的引數是一個size_t型別，指明瞭需要分配記憶體的規模。operator new函式可以被每個C++類作為成員函式過載。也可以作為全域性函式過載：void * operator new (std::size_t) throw(std::bad_alloc);void operator delete(void*) throw();記憶體需要回收的話,呼叫對應的operator delete()函式。例如，在new運算子表示式的第二步，呼叫建構函式初始化記憶體時如果丟擲異常，異常處理機制在棧展開時，要回收在new運算子表示式的第一步已經動態分配到的記憶體，這時就會自動呼叫對應operator delete()函式。陣列形式的operator new[](size_t size)函式.new Type[]運算子，用來動態建立一個物件陣列。這需要呼叫陣列基型別內部定義的void* operator new[ ](size_t)函式來分配記憶體。如果陣列基型別沒有定義該函式，則呼叫全域性的void* operator new[ ](size_t)函式來分配記憶體。在中聲明瞭void* operator new[ ](size_t)全域性函式：void * operator new[] (std::size_t) throw(std::bad_alloc);void operator delete[](void*) throw();void* operator new(size_t,void*).operator new(size_t,void*)函式用於帶位置的new運算子呼叫。C++標準庫已經提供了operator new(size_t,void*)函式的實現，包含標頭檔案即可。這個實現只是簡單的把引數的指定的地址返回，帶位置的new運算子就會在該地址上呼叫建構函式來初始化物件：// Default placement versions of operator new.// Default placement versions of operator delete.禁止重定義這4個函式。因為都已經作為的內聯函數了。在使用時，實際上不需要codice_13對應的placement delete函式，只應在placement new運算子表示式在第二步呼叫建構函式丟擲異常時被異常處理機制的棧展開操作自動呼叫。保證不丟擲異常的operator new函式.C++標準庫的中還提供了一個nothrow的實現，使用者可寫自己的函式替代：void* operator new(std::size_t, const std::nothrow_t&amp;) throw();void* operator new[](std::size_t, const std::nothrow_t&amp;) throw();void operator delete(void*, const std::nothrow_t&amp;) throw();void operator delete[](void*, const std::nothrow_t&amp;) throw();自行定製引數的operator new函式.這種函式被自行定製引數的new算符呼叫。需要由使用者自行定義，以確定分配記憶體時的行為：operator new(size_,Type1, Type2, ... );例如：char data[1000][sizeof(int)];inline void* operator new(size_t ,int n)return data[n];void foo(){int *p=new(6) int(102); //把整型物件建立在data的第六個單元上