共用方式為


new 運算子 (C++)

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

語法

new-expression
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt

new-placement
( expression-list )

new-type-id
type-specifier-seq new-declaratoropt

new-declarator
ptr-operator new-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 中於受控堆積上建立物件的相關資訊,請參閱 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 不能包含 constvolatile、類別宣告或列舉宣告。 下列運算式的格式不正確:

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

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

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

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

如果您使用運算子 new 而不使用任何額外的引數,並使用 /GX/EHa/EHs 選項進行編譯,則編譯器會在建構函式擲回例外狀況時產生呼叫運算子 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 靜態成員函式。

當編譯器遇到用來配置類型 T 物件的 new 運算子時,它會發出對 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 具有成員 operator new,則具有 T *TObject = new ( 0x0040 ) T; 之類的 new-placement 欄位的運算式會轉譯為 T *TObject = T::operator new( sizeof( T ), 0x0040 );,否則為 T *TObject = ::operator new( sizeof( T ), 0x0040 );

new-placement 欄位的原始用途是允許在使用者指定的位址配置取決於硬體的物件。

注意

雖然上述範例只示範 new-placement 欄位中的一個引數,但利用這種方式可額外傳遞到 operator new 的引數數量不受限制。

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

T *TObject = ::new TObject;

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

另請參閱

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