new
operator (C++)
嘗試配置和初始化指定或預留位置類型之物件的物件或陣列,並傳回物件適當型別的非零指標(或陣列的初始物件)。
語法
new-expression
:
::
opt opt opt new-type-id
new-initializer
new
new-placement
::
opt opt opt new-initializer
)
type-id
(
new
new-placement
new-placement
:
(
expression-list
)
new-type-id
:
type-specifier-seq
new-declarator
opt
new-declarator
:
ptr-operator
new-declarator
opt
noptr-new-declarator
noptr-new-declarator
:
[
expression
]
attribute-specifier-seq
opt
noptr-new-declarator
[
constant-expression
]
attribute-specifier-seq
opt
new-initializer
:
(
expression-list
opt)
braced-init-list
備註
如果失敗, new
則傳回零或擲回例外狀況。 如需詳細資訊,請參閱 new
和 delete
運算子 。 您可以撰寫自訂例外狀況處理常式,並以您的函式名稱作為其引數呼叫 _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-id
或type-id
之指標型別之 物件的指標。 程式會使用此指標來存取新配置的物件。
運算子 new
會叫用 函式 operator new
。 對於任何型別的陣列,以及不是 class
、 struct
或 union
型別的物件,會呼叫全域函式 來 ::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
運算子。
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應