1. 程式人生 > >new,malloc和::operator new

new,malloc和::operator new

執行程式離不開記憶體管理,c記憶體管理離不開malloc和free,c++記憶體管理離不開new和delete。

雖說都是為了申請記憶體和釋放記憶體,但new和malloc還是有區別的,這裡總結下:

兩者聯絡自不必多說,都是為了在堆上動態的申請和釋放記憶體。

區別在於:

1.new和delete屬於操作符,而malloc和free其實是兩個系統函式。

2.new在申請記憶體時候返回的是指定型別的指標,申請記憶體大小自動計算;malloc在申請記憶體時候返回的是void*指標,並且在申請時要指明申請記憶體的大小,以引數形式傳進去。

char * a = new char;
char * b = (char*)malloc(sizeof(char));

3.new在申請完記憶體後會呼叫該型別的建構函式,也就是說new在申請完記憶體後會初始化這段記憶體;malloc則單純的多,申請完指定大小的記憶體就完事,至於這段記憶體要用作何用,malloc並不關心。

4.內建型別如int,char,float等等均可以用new和malloc申請記憶體,但是非內建型別,也就是程式設計師新建的型別不能使用malloc而必須使用new。我覺得出現這個現象的原因是因為c和c++兩者區別導致的,從某種角度說,c是c++的子集,c++在c基礎上又增加了模板和類等新東西,new和delete的出現是為了適應class的構造與析構,而malloc和free設計之初只是為了適應c的記憶體管理,所以不能把class的構造和析構強加於malloc和free身上。

5.new和delete配對使用,malloc和free配對使用。

以上是new/delete和malloc/free的區別,malloc/free背後的機制相對簡單,只是分配/釋放指定大小的記憶體,而new/delete背後的機制就複雜些:

一般,在使用new時,編譯器會執行兩步操作:

1.呼叫::operator new()分配計算後的記憶體;

2.在分配好的記憶體上呼叫該型別的建構函式進行初始化。

delete則剛好相反:

1.呼叫物件的解構函式;

2.使用::operator delete()釋放記憶體。

new/delete各自背後的兩步操作是無法規避的,由於new/delete是操作符,所以實現形式上不能按照程式設計師需要進行改變,但是::operator new()和::operator delete()是兩個屬於std中的函式,其作用與malloc和free相似,都是為了分配足夠大的記憶體,只是它們並不關心記憶體的初始化問題。

先看兩個operator的一般呼叫方式:

void* operator new(size_t);

void operator delete(void*);

是不是與malloc和free很像呢?

operator new更具體的形式有三種:

//異常丟擲形式:
void* operator new (std::size_t size) throw (std::bad_alloc);
//不丟擲異常形式
 void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();
//placement形式
void* operator new (std::size_t size, void* ptr) throw();

使用new或delete時候,預設呼叫std::operator new()或std::operator delete();既然是函式就可以過載,程式設計師可以按照實際需要過載這兩個函式。看下面這個例子:

class A
{
public:
	A(){
	  cout<<"A constructor"<<endl;
	}
	void* operator new(size_t size){
	  cout<<"this is A's new"<<endl;
          return ::operator new(size);
	}
	void operator delete(void* ptr){
	  cout<<"this is A's delete"<<endl;
	  return ::operator delete(ptr);
	}
	~A(){
	  cout<<"A destructor"<<endl;
	}
};
int _tmain(int argc, _TCHAR* argv[])
{
  A *a = new A;
  delete a;
  return 0;
}
執行結果:

雖然我們不能改變new/delete的行為,但是通過過載operator new() 和 operator delete()我們可以實現自己想要的記憶體管理方式,這在記憶體池的實現中十分關鍵。

關於operator new有幾點要注意:
(1)當無法滿足所要求分配的空間時,則
        ->如果有new_handler,則呼叫new_handler,否則
        ->如果沒要求不丟擲異常(以nothrow引數表達),則執行bad_alloc異常,否則
        ->返回0
(2)過載時,返回型別必須宣告為void*
(3)過載時,第一個引數型別必須為表達要求分配空間的大小(位元組),型別為size_t
(4)過載時,可以帶除(3)以外的其它引數