new檔案用來管理c++的動態記憶體,這個檔案宣告瞭幾個全域性空間的函式(不是std空間的函式,全域性空間的函式呼叫時是用全域性作用域解析符),包括operator new 和operator delete的過載 ,這些函式用於處理動態儲存空間請求。
其new的標頭檔案原始碼
#ifndef _NEW #define _NEW #include <cstddef> #include <exception> extern "C++" { namespace std { //注意此空間內函式或者變數處於std空間,使用時需要新增std::呼叫 /** * 當記憶體分配錯誤的時候丟擲bad_alloc異常 */ class bad_alloc : public exception { public: bad_alloc() throw() { } virtual ~bad_alloc() throw(); }; //當記憶體分配失敗時用此結構體替代異常,使用嵌入式環境,嵌入式環境沒有異常功能 struct nothrow_t { }; extern const nothrow_t nothrow; ///當記憶體分配失敗時,呼叫new_handler ///new_handler試著去分配更多得儲存空間,當且僅當申請記憶體成功時,才會返 ///否則丟擲bad_alloc異常或者終止程式(呼叫abort或者exit) typedef void (*new_handler)(); new_handler set_new_handler(new_handler) throw(); } // namespace std //全域性空間函式,呼叫時加上作用域解析符,如::operator new () 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(); 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(); //placement operator new/delete inline void* operator new(std::size_t, void* __p) throw() { return __p; } inline void* operator new[](std::size_t, void* __p) throw() { return __p; } inline void operator delete (void*, void*) throw() { } inline void operator delete[](void*, void*) throw() { } } // extern "C++" #endif
1、關於new operator與operator new
operator new() 僅僅分配記憶體空間,是對malloc的一個封裝,返回的是一個void *,如
int* a = (int *)::operator new(sizeof(int));
只是對a分配了空間,通過vs2012進行除錯你會發現operator new 的實現如下:其主要是呼叫malloc(size),而沒有對記憶體進行初始化
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc) { // try to allocate size bytes void *p; while ((p = malloc(size)) == 0) if (_callnewh(size) == 0) { // report no memory static const std::bad_alloc nomem; _RAISE(nomem); } return (p); }
對於new operator先呼叫operator new分配記憶體空間,然後呼叫建構函式初始化
#include <iostream> using namespace std; class Foo{ public: Foo(){ cout<<"Foo constructor"<<endl; a = 10; } //對operator new進行重寫 void* operator new(size_t size){ cout<<"Foo operator new"<<endl; return ::operator new(size); } int a; }; int main(){ Foo* f1 =(Foo *) ::operator new(sizeof(Foo)); cout<<f1->a<<endl; Foo* f2 = new Foo(); cout<<f2->a<<endl; } /*************** 結果為: 3420040 Foo operator new Foo constructor 10 *****************/
由於operator new 只是分配空間未呼叫建構函式,所以公有變數未初始化,是個隨機值,
而new Foo() 先呼叫operator new 然後再建構函式,所以會先出現Foo operator new
2、關於placement new(定位放置new)
placement new 是operator new的一個過載的版本,如果你想在已經分配的記憶體中建立一個物件,這時不能使用new。而placement new永許你在一個已經分配好的記憶體中(棧或者堆中)構造一個新的物件,原型中void* p實際就是指向一個已經分配好的記憶體緩衝區的首地址。c++支援placement operator new,能夠在預先分配的緩衝區中構造物件,避免new記憶體分配時查詢記憶體和分配記憶體的時間,而且由於記憶體已經分配,沒有記憶體分配失敗的危險,在記憶體池,垃圾回收器,和效能或異常安全可以使用
char *buf = new char[sizeof(string)]; // pre-allocated buffer string *p = new (buf) string("hi"); // placement new
char memory[sizeof(Foo)]; void* place = memory; Foo* f = new(place) Foo();
3、關於set_new_handler
new_handler型別的函式是預設記憶體申請函式(operator new和operator new[])申請記憶體失敗,會被呼叫。
new_handler函式會試圖為新的記憶體申請請求提供更多的可用空間。當且僅當,函式成功地提供了更多的可用空間,它才返回。
否則,要麼丟擲bad_alloc異常(或bad_alloc派生類)要麼終止程式(比如呼叫abort或exit)。
如果new_handler函式返回(即,它提供了更多可用空間)後,當記憶體申請函式申請指定的記憶體空間失敗時,它會被再次呼叫,或直到new_handle函式不返回或被替換。
#include <iostream> #include <new> char* memoryPool = NULL; void my_new_handler(){ if(NULL != memoryPool){ // 刪除一些不用的記憶體 delete[] memoryPool; memoryPool = NULL; }else{ //沒有足夠的記憶體 throw std::bad_alloc(); } return ; } int main(){ std::set_new_handler(my_new_handler); memoryPool = new char[512*1024*1024]; if(memoryPool == NULL){ std::cout<<"allocator fail"<<std::endl; return -1; } char *p = NULL; for(int i = 0 ; i < 4; ++ i){ p = new char[256*1024*1024]; std::cout<<i+1<<" allocator 512M "<<p<<std::endl; } return 0; }