C++中的new和delete

C++中的new/delete運算符有兩種含義:

1.  new/delete operator,內置的運算符(即newdelete這兩個keywords),用來分配內存(需要調用2中描述的運算符)並初始化變量/對象(調用構造函數等)。

2.  operator new/delete,用來進行內存分配和回收的運算符,只負責內存的分配和回收。

看下面的例子:

class MyClass {…};

MyClass *p = new MyClass; // there should be a default constructor in MyClass

 

這個例子中的 new1中描述的運算符。實際上它執行如下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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章