C++中的new/delete運算符有兩種含義:
1. new/delete operator,內置的運算符(即new和delete這兩個keywords),用來分配內存(需要調用2中描述的運算符)並初始化變量/對象(調用構造函數等)。
2. operator new/delete,用來進行內存分配和回收的運算符,只負責內存的分配和回收。
看下面的例子:
class MyClass {…}; MyClass *p = new MyClass; // there should be a default constructor in MyClass |
這個例子中的 new是1中描述的運算符。實際上它執行如下3個過程:
1). 調用2中描述的new算符分配內存;
2). 調用構造函數完成對象的創建和初始化(因爲需要完成ctor和dtor的自動調用,所以C++新增了new和delete這兩個關鍵字,C中的malloc()和free()是函數,無法完成這樣的任務);
3). 返回相應的指針。
2中描述的算符在C++中有3種定義,下面的代碼片段摘自new文件(CentOS 5.4, /usr/include/c++/4.1.2/new)。
// plain new/delete // 帶拋出異常的版本 void* operator new(std::size_t) throw (std::bad_alloc); void* operator new[](std::size_t) throw (std::bad_alloc); void operator delete(void*) throw(); void operator delete[](void*) throw();
// nothrow new/delete // 不拋出異常的版本 void* operator new(std::size_t, const std::nothrow_t&) throw(); void* operator new[](std::size_t, const std::nothrow_t&) throw(); void operator delete(void*, const std::nothrow_t&) throw(); void operator delete[](void*, const std::nothrow_t&) throw();
// Default placement versions of operator new. inline void* operator new(std::size_t, void* __p) throw() { return __p; } inline void* operator new[](std::size_t, void* __p) throw() { return __p; }
// Default placement versions of operator delete. inline void operator delete (void*, void*) throw() { } inline void operator delete[](void*, void*) throw() { } |
因爲1中描述的new/delete最終會調用2中描述的new/delete,而2中提及的new/delete共有上述3種版本,那麼1中提及的new/delete(主要是new)則有3種調用方式。(補充:new operator的3種調用方式用來告訴編譯器調用哪個operator new,而delete operator則只有一種調用方式,operator delete的3個版本主要是給編譯器使用的,如構造函數拋出異常時調用operator new對應的operator delete來釋放內存。)
// 1. plain new try { char *p = new char[10000000]; … delete []p; } catch (const std::bad_alloc &ex) { cout << ex.what() << endl; }
// 2. nothrow new char *p = new(nothrow) char[10000000]; if (NULL == p) cout << “allocation failed!” << endl; … delete []p;
// 3. placement new char *p = new(nothrow) char[4]; if (NULL == p) { cout << “allocation failed!” << endl; exit(-1); } … long *q = new(p) long(1000); … delete []p; |
爲了證明1中提及的new/delete的工作方式,來看下面的演示代碼:
#include <iostream>
using namespace std;
class Demo { public: Demo() : __x(0) { static int counter = 0; cout << "default ctor is called: " << ++counter << endl; }
~Demo() { static int counter = 0; cout << "dtor is called: " << ++counter << endl; }
// 這裏我們對global作用域中帶異常拋出版本的new/delete進行重載 static void* operator new(std::size_t) throw (std::bad_alloc); static void* operator new[](std::size_t) throw (std::bad_alloc);
static void operator delete(void*) throw(); static void operator delete[](void*) throw();
private: int __x; };
void* Demo::operator new(std::size_t size) throw (std::bad_alloc) { cout << "operator new is called, size = " << size << endl;
// 此處我們直接調用global作用域中的new return ::operator new(size); }
void* Demo::operator new[](std::size_t size) throw (std::bad_alloc) { cout << "operator new[] is called, size = " << size << endl;
// 此處我們直接調用global作用域中的new[] return ::operator new[](size); }
void Demo::operator delete(void *p) throw() { cout << "operator delete is called" << endl;
// 此處我們直接調用global作用域中的delete ::operator delete(p); }
void Demo::operator delete[](void *p) throw() { cout << "operator delete[] is called" << endl;
// 此處我們直接調用global作用域中的delete[] ::operator delete[](p); }
int main(void) { try { Demo *p = new Demo; delete p;
Demo *pa = new Demo[3]; delete []pa; } catch(const std::bad_alloc &ex) { cout << ex.what() << endl; }
return 0; }
|
程序的輸出結果如下(CentOS 5.4, g++ 4.1.2):
operator new is called, size = 4
default ctor is called: 1
dtor is called: 1
operator delete is called
operator new[] is called, size = 16 (猜猜這裏爲什麼是16)
default ctor is called: 2
default ctor is called: 3
default ctor is called: 4
dtor is called: 2
dtor is called: 3
dtor is called: 4
operator delete[] is called
從上面的輸出可以看出當new一個對象的時候,重載的operator new會先被調用,然後是構造函數;delete一個對象時,則先調用析構函數,然後調用重載的operator delete。