new operator (C++)

嘗試配置和初始化指定或預留位置類型之物件的物件或陣列,並傳回物件適當型別的非零指標(或陣列的初始物件)。

語法

new-expression
::opt opt opt new-type-idnew-initializernewnew-placement
::opt opt opt new-initializer)type-id(newnew-placement

new-placement
( expression-list )

new-type-id
type-specifier-seqnew-declaratoropt

new-declarator
ptr-operatornew-declaratoropt
noptr-new-declarator

noptr-new-declarator
[expression]attribute-specifier-seqopt
noptr-new-declarator[constant-expression]attribute-specifier-seqopt

new-initializer
(expression-listopt)
braced-init-list

備註

如果失敗, new 則傳回零或擲回例外狀況。 如需詳細資訊,請參閱 newdelete 運算子 。 您可以撰寫自訂例外狀況處理常式,並以您的函式名稱作為其引數呼叫 _set_new_handler 執行時間程式庫函式,以變更此預設行為。

如需如何在 C++/CLI 和 C++/CX 的 Managed 堆積上建立物件的資訊,請參閱 gcnew

注意

Microsoft C++ 元件延伸模組 (C++/CX) 提供關鍵字的支援 new ,以新增 vtable 位置專案。 如需詳細資訊,請參閱 new (vtable 中的新位置)

new 用來配置 C++ 類別物件的記憶體時,會在配置記憶體之後呼叫 物件的建構函式。

delete使用 運算子來解除配置 運算子所 new 配置的記憶體。 delete[]使用 運算子來刪除運算子所 new 配置的陣列。

下列範例會先配置然後再釋放大小為 dim 乘以 10 個字元的二維陣列。 配置多維度陣列時,除了第一個維度以外的所有維度都必須是評估為正值的常數運算式。 最左邊的陣列維度可以是任何評估為正值的運算式。 使用 new 運算子配置陣列時,第一個維度可以是零; new 運算子會傳回唯一指標。

char (*pchar)[10] = new char[dim][10];
delete [] pchar;

type-id不能包含 const 、、 volatile 類別宣告或列舉宣告。 下列運算式的格式不正確:

volatile char *vch = new volatile char[20];

new運算子不會配置參考型別,因為它們不是物件。

new運算子無法用來配置函式,但可用來配置函式的指標。 下列範例會配置然後再釋放含七個傳回整數之函式指標的陣列。

int (**p) () = new (int (*[7]) ());
delete p;

如果您使用 運算子 new 而不使用任何額外的引數,並使用 、 /EHa/EHs 選項進行編譯 /GX ,則編譯器會在建構函式擲回例外狀況時產生呼叫運算子 delete 的程式碼。

下列清單描述 的 new 文法元素:

new-placement
如果您多載 new ,提供傳遞額外引數的方式。

type-id
指定要配置的型別;它可以是內建或使用者定義型別。 如果類型規格是複雜的,請以括號括住類型規格以強制繫結的順序。 此類型可能是編譯器決定其類型的預留位置 ( auto )。

new-initializer
提供初始化物件的值。 無法為數組指定初始化運算式。 只有當 類別具有預設建構函式時,運算子 new 才會建立 物件的陣列。

noptr-new-declarator
指定陣列的界限。 配置多維度陣列時,除了第一個維度以外的所有維度都必須是評估為可轉換成 std::size_t 之正值的常數運算式。 最左邊的陣列維度可以是任何評估為正值的運算式。 attribute-specifier-seq會套用至相關聯的陣列類型。

範例:配置和釋放字元陣列

下列程式碼範例會配置一個字元陣列和一個 CName 類別物件,然後加以釋放。

// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>

class CName {
public:
   enum {
      sizeOfBuffer = 256
   };

   char m_szFirst[sizeOfBuffer];
   char m_szLast[sizeOfBuffer];

public:
   void SetName(char* pszFirst, char* pszLast) {
     strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
     strcpy_s(m_szLast, sizeOfBuffer, pszLast);
   }

};

int main() {
   // Allocate memory for the array
   char* pCharArray = new char[CName::sizeOfBuffer];
   strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");

   // Deallocate memory for the array
   delete [] pCharArray;
   pCharArray = NULL;

   // Allocate memory for the object
   CName* pName = new CName;
   pName->SetName("Firstname", "Lastname");

   // Deallocate memory for the object
   delete pName;
   pName = NULL;
}

範例: new 運算子

如果您使用運算子的 new 放置形式(具有比大小更多的引數的表單),如果建構函式擲回例外狀況,編譯器就不支援運算子的 delete 放置形式。 例如:

// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
   A(int) { throw "Fail!"; }
};
void F(void) {
   try {
      // heap memory pointed to by pa1 will be deallocated
      // by calling ::operator delete(void*).
      A* pa1 = new A(10);
   } catch (...) {
   }
   try {
      // This will call ::operator new(size_t, char*, int).
      // When A::A(int) does a throw, we should call
      // ::operator delete(void*, char*, int) to deallocate
      // the memory pointed to by pa2.  Since
      // ::operator delete(void*, char*, int) has not been implemented,
      // memory will be leaked when the deallocation can't occur.

      A* pa2 = new(__FILE__, __LINE__) A(20);
   } catch (...) {
   }
}

int main() {
   A a;
}

使用 初始化配置的物件 new

選擇性 new-initializer 欄位包含在 運算子的文法 new 中。 此欄位可讓新的物件使用使用者定義的建構函式初始化。 如需初始化如何完成的詳細資訊,請參閱 初始化運算式 。 下列範例說明如何搭配 new 運算子使用初始化運算式:

// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
    // Define default constructor and a constructor that accepts
    //  an initial balance.
    Acct() { balance = 0.0; }
    Acct( double init_balance ) { balance = init_balance; }
private:
    double balance;
};

int main()
{
    Acct *CheckingAcct = new Acct;
    Acct *SavingsAcct = new Acct ( 34.98 );
    double *HowMuch = new double { 43.0 };
    // ...
}

在此範例中,物件 CheckingAcct 是使用 new 運算子來配置,但未指定預設初始化。 因此,會呼叫 類別 Acct() 的預設建構函式 。 然後,物件 SavingsAcct 會以相同的方式配置,不同之處在于它已明確初始化為 34.98。 由於 34.98 的類型為 double ,因此會呼叫接受該型別引數的建構函式來處理初始化。 最後,非類別類型 HowMuch 會初始化為 43.0。

如果物件是類別類型,而且該類別具有建構函式(如上述範例所示),則只有在符合下列其中一個條件時,才能由 new 運算子初始化物件:

  • 初始化運算式中提供的引數符合建構函式的引數。

  • 類別有預設建構函式 (可以在沒有引數的情況下呼叫的建構函式)。

使用 new 運算子配置陣列時,無法完成明確個別元素初始化;如果存在,則只會呼叫預設建構函式。 如需詳細資訊,請參閱 預設自 變數。

如果記憶體配置失敗 ( operator new 傳回值為 0),則不會完成初始化。 此行為可防止嘗試初始化不存在的資料。

如同函式呼叫,未定義初始化運算式的順序。 此外,在記憶體配置發生之前,您不應該完全依賴這些運算式進行評估。 如果記憶體配置失敗,且 new 運算子傳回零,則初始化運算式中的某些運算式可能無法完全評估。

設定物件存留期 new

當定義物件的範圍結束時,不會終結與 運算子一起 new 配置的物件。 new因為 運算子會傳回其配置之物件的指標,所以程式必須定義具有適當範圍的指標,才能存取和刪除這些物件。 例如:

// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
    // Use new operator to allocate an array of 20 characters.
    char *AnArray = new char[20];

    for( int i = 0; i < 20; ++i )
    {
        // On the first iteration of the loop, allocate
        //  another array of 20 characters.
        if( i == 0 )
        {
            char *AnotherArray = new char[20];
        }
    }

    delete [] AnotherArray; // Error: pointer out of scope.
    delete [] AnArray;      // OK: pointer still in scope.
}

一旦指標 AnotherArray 超出範例中的範圍,就無法刪除物件。

運作方式 new

new-expression(包含 運算子的 new 運算式) 會執行三件事:

  • 為要配置的物件找出並保留存放區。 當這個階段完成時,會配置正確的儲存體數量,但還不是 物件。

  • 將物件初始化。 初始化完成後,就會出現使配置存放區成為物件的足夠資訊。

  • 傳回衍生自 new-type-idtype-id 之指標型別之 物件的指標。 程式會使用此指標來存取新配置的物件。

運算子 new 會叫用 函式 operator new 。 對於任何型別的陣列,以及不是 classstructunion 型別的物件,會呼叫全域函式 來 ::operator new 配置儲存體。 類別類型物件可以根據每個類別定義自己的 operator new 靜態成員函式。

當編譯器遇到 new 運算子來配置 類型的 T 物件時,它會發出呼叫 T::operator new( sizeof(T) ) ,如果沒有定義使用者定義 operator new::operator new( sizeof(T) ) 則為 。 運算子如何 new 為物件配置正確的記憶體數量。

注意

的引數 operator new 為 類型 std::size_t 。 此類型定義于 direct.h、malloc.h、 < memory.h >> 、 < search.h > 、stddef.h > 、 << stdio.h > 、stdlib.h > 、 << string.h 和 < time.h >> 中。 <><

文法中的選項允許指定 new-placement (請參閱運算子 文法 new )。 new-placement參數只能用於 的使用者定義實作 operator new ;它允許將額外的資訊傳遞至 operator new 。 如果類別 T 具有 new-placement 成員 operator new ,則具有 之類的 T *TObject = new ( 0x0040 ) T; 欄位的運算式會轉譯為 T *TObject = T::operator new( sizeof( T ), 0x0040 ); ,否則為 T *TObject = ::operator new( sizeof( T ), 0x0040 );

欄位的 new-placement 最初意圖是允許在使用者指定的位址配置硬體相依物件。

注意

雖然上述範例在 new-placement 欄位中只顯示一個引數,但不會限制可透過這種方式傳遞 operator new 多少個額外引數。

operator new即使已針對類別類型 T 定義 ,您也可以明確地使用全域運算子 new ,如下列範例所示:

T *TObject = ::new TObject;

範圍解析運算子 ( :: ) 會強制使用全域 new 運算子。

另請參閱

具有一元運算子的運算式
關鍵字
newdelete 運算子