c++ 關於new檔案

OpenSoucre發表於2014-05-19

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;
}

 

相關文章