new
和 delete
運算子
C++ 支援使用 new
和 delete
運算子來動態配置和解除配置物件。 這些運算子會配置記憶體給集區中稱為 免費存放區 的物件(也稱為 堆積 )。 運算子 new
會呼叫特殊函 operator new
式,而 運算子會 delete
呼叫特殊函式 operator delete
。
如需 C 執行時間程式庫和 C++ 標準程式庫中的程式庫檔案清單,請參閱 CRT 程式庫功能 。
運算子 new
編譯器會將這類語句轉譯為對函 operator new
式的呼叫:
char *pch = new char[BUFFER_SIZE];
如果要求為零位元組的儲存體,則 operator new
傳回相異物件的指標。 也就是說,重複呼叫以 operator new
傳回不同的指標。
如果配置要求記憶體不足, operator new
則會 std::bad_alloc
擲回例外狀況。 或者,如果您已使用放置表單 new(std::nothrow)
,或已在非擲回 operator new
支援中連結,則會傳回 nullptr
。 如需詳細資訊,請參閱 配置失敗行為 。
下表說明函式的兩個 operator new
範圍。
函式的範圍 operator new
運算子 | 範圍 |
---|---|
::operator new |
全域 |
class-name::operator new |
類別 |
的第一個引數 operator new
必須是 類型 size_t
,且傳回型別一律 void*
為 。
當運算子用來配置內建型別的物件、不包含使用者定義 operator new
函式的類別類型物件,以及任何類型的陣列時 new
,就會呼叫全域 operator new
函式。 new
當 運算子用來配置定義 之類別類型的 operator new
物件時,會呼叫該類別的 operator new
。
operator new
針對類別定義的函式是靜態成員函式(不能是虛擬的),該函式會隱藏該類別類型的物件的全域 operator new
函式。 請考慮用來配置記憶體並將記憶體設定為指定值的情況 new
:
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// For discrete objects of type Blanks, the global operator new function
// is hidden. Therefore, the following code allocates an object of type
// Blanks and initializes it to 0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
括弧中 new
提供的引數會當做 chInit
引數傳遞至 Blanks::operator new
。 不過,全域 operator new
函式會隱藏,導致下列程式碼產生錯誤:
Blanks *SomeBlanks = new Blanks;
編譯器支援類別宣告中的成員陣列 new
和 delete
運算子。 例如:
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
配置失敗行為
new
C++ 標準程式庫中的 函式支援 C++ 標準中指定的行為,因為 C++98。 當配置要求記憶體不足時, operator new
會 std::bad_alloc
擲回例外狀況。
舊版 C++ 程式碼傳回失敗配置的 Null 指標。 如果您有預期非擲回版本的 new
程式碼,請將程式連結至 nothrownew.obj
。 檔案會 nothrownew.obj
以配置失敗時傳 nullptr
回的版本取代全域 operator new
。 operator new
不再擲回 std::bad_alloc
。 如需和其他連結器選項檔案的詳細資訊 nothrownew.obj
,請參閱 連結選項 。
您無法將檢查全域 operator new
例外狀況的程式碼與檢查相同應用程式中 Null 指標的程式碼混合在一起。 不過,您仍然可以建立以不同方式運作的類別本機 operator new
。 這種可能性表示編譯器預設必須以防禦方式採取行動,並在呼叫中包含 new
Null 指標傳回的檢查。 如需優化這些編譯器檢查方式的詳細資訊,請參閱 /Zc:throwingnew
。
處理記憶體不足
您測試運算式中失敗配置 new
的方式取決於您使用的是標準例外狀況機制,還是使用傳 nullptr
回。 標準 C++ 預期配置器會擲回 std::bad_alloc
或衍生自 std::bad_alloc
的類別。 您可以處理這類例外狀況,如此範例所示:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
try {
int *pI = new int[BIG_NUMBER];
}
catch (bad_alloc& ex) {
cout << "Caught bad_alloc: " << ex.what() << endl;
return -1;
}
}
當您使用 nothrow
的形式 new
時,您可以測試組態失敗,如下列範例所示:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new(nothrow) int[BIG_NUMBER];
if ( pI == nullptr ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
當您使用 nothrownew.obj
檔案來取代全域 operator new
時,您可以測試失敗的記憶體配置,如下所示:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new int[BIG_NUMBER];
if ( !pI ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
您可以為失敗的記憶體配置要求提供處理常式。 可以撰寫自訂復原常式來處理這類失敗。 例如,它可以釋放一些保留的記憶體,然後允許配置再次執行。 如需詳細資訊,請參閱_set_new_handler
。
運算子 delete
使用 運算子動態配置的 new
記憶體可以使用 運算子釋放 delete
。 delete 運算子會呼叫 operator delete
函式,此函式會將記憶體釋放回可用的集區。 delete
使用 運算子也會呼叫類別解構函式(如果有的話)。
有全域和類別範圍的函式 operator delete
。 指定類別只能定義一個 operator delete
函式;如果已定義,則會隱藏全域 operator delete
函式。 全域 operator delete
函式一律會針對任何類型的陣列呼叫。
全域 operator delete
函式。 全域 operator delete
和類別成員 operator delete
函式有兩種形式:
void operator delete( void * );
void operator delete( void *, size_t );
指定類別只能有上述兩種表單的其中一個。 第一個表單採用 類型的 void *
單一引數,其中包含要解除配置之物件的指標。 第二種形式大小解除配置會採用兩個引數:第一種是要解除配置的記憶體區塊指標,第二種是要解除配置的位元組數目。 這兩種表單的傳回類型為 void
( operator delete
無法傳回值)。
第二個表單的意圖是加快搜尋要刪除之物件的正確大小類別。 此資訊通常不會儲存在配置本身附近,而且可能未快取。 當基類的函式用來刪除衍生類別的物件時 operator delete
,第二個表單很有用。
函式是靜態的 operator delete
,因此不能是虛擬的。 函 operator delete
式會遵守存取控制,如 Member-存取控制 中所述 。
下列範例顯示設計來記錄記憶體配置和解除配置的使用者定義 operator new
和 operator delete
函式:
#include <iostream>
using namespace std;
int fLogMemory = 0; // Perform logging (0=no; nonzero=yes)?
int cBlocksAllocated = 0; // Count of blocks allocated.
// User-defined operator new.
void *operator new( size_t stAllocateBlock ) {
static int fInOpNew = 0; // Guard flag.
if ( fLogMemory && !fInOpNew ) {
fInOpNew = 1;
clog << "Memory block " << ++cBlocksAllocated
<< " allocated for " << stAllocateBlock
<< " bytes\n";
fInOpNew = 0;
}
return malloc( stAllocateBlock );
}
// User-defined operator delete.
void operator delete( void *pvMem ) {
static int fInOpDelete = 0; // Guard flag.
if ( fLogMemory && !fInOpDelete ) {
fInOpDelete = 1;
clog << "Memory block " << cBlocksAllocated--
<< " deallocated\n";
fInOpDelete = 0;
}
free( pvMem );
}
int main( int argc, char *argv[] ) {
fLogMemory = 1; // Turn logging on
if( argc > 1 )
for( int i = 0; i < atoi( argv[1] ); ++i ) {
char *pMem = new char[10];
delete[] pMem;
}
fLogMemory = 0; // Turn logging off.
return cBlocksAllocated;
}
上述程式碼可用來偵測「記憶體外泄」,也就是配置於免費存放區但從未釋放的記憶體。 為了偵測流失,全域 new
和 delete
運算子會重新定義以計算記憶體的配置和解除配置。
編譯器支援類別宣告中的成員陣列 new
和 delete
運算子。 例如:
// spec1_the_operator_delete_function2.cpp
// compile with: /c
class X {
public:
void * operator new[] (size_t) {
return 0;
}
void operator delete[] (void*) {}
};
void f() {
X *pX = new X[5];
delete [] pX;
}
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應