條款八: 寫operator new和operator delete時要遵循常規

來源:互聯網
上載者:User

標籤:style   blog   color   代碼   div   c++   new   size   

自己重寫operator new時(條款10解釋了為什麼有時要重寫它),很重要的一點是函數提供的行為要和系統預設的operator new一致。實際做起來也就是:要有正確的傳回值;可用記憶體不夠時要調用出錯處理函數(見條款7);處理好0位元組記憶體請求的情況。此外,還要避免不小心隱藏了標準形式的new,不過這是條款9的話題。

有關傳回值的部分很簡單。如果記憶體配置請求成功,就返回指向記憶體的指標;如果失敗,則遵循條款7的規定拋出一個std::bad_alloc類型的異常。operator new實際上會不只一次地嘗試著去分配記憶體,它要在每次失敗後調用出錯處理函數,還期望出錯處理函數能想辦法釋放別處的記憶體。只有在指向出錯處理函數的指標為空白的情況下,operator new才拋出異常。

c++標準要求,即使在請求分配0位元組記憶體時,operator new也要返回一個合法指標。

非類成員形式的operator new的虛擬碼看起來會象下面這樣:

void * operator new(size_t size)        // operator new還可能有其它參數{                                        if (size == 0) {                      // 處理0位元組請求時,    size = 1;                           // 把它當作1個位元組請求來處理  }                                       while (1) {    分配size位元組記憶體;    if (分配成功)      return (指向記憶體的指標);    // 分配不成功,找出當前出錯處理函數    new_handler globalhandler = set_new_handler(0);    set_new_handler(globalhandler);    if (globalhandler) (*globalhandler)();    else throw std::bad_alloc();  }}

 

處理零位元組請求的技巧在於把它作為請求一個位元組來處理。

operator new經常會被子類繼承,這會導致某些複雜性。大多數針對類所寫的operator new(包括條款10中的那種)都是只為特定的類設計的,不是為所有的類,也不是為它所有的子類設計的。這意味著,對於一個類x的operator new來說,函數內部的行為在涉及到對象的大小時,都是精確的sizeof(x):不會大也不會小。但由於存在繼承,基類中的operator new可能會被調用去為一個子類對象分配記憶體:

class base {public:  static void * operator new(size_t size);  ...};class derived: public base       // derived類沒有聲明operator new{ ... };                         // derived *p = new derived;        // 調用base::operator new

如果base類的operator new不想費功夫專門去處理這種情況——這種情況出現的可能性不大——那最簡單的辦法是把這個“錯誤”數量的記憶體配置請求轉給標準operator new來處理,象下面這樣:

void * base::operator new(size_t size){  if (size != sizeof(base))             // 如果數量“錯誤”,讓標準operator new    return ::operator new(size);        // 去處理這個請求                                        //  ...                                   // 否則處理這個請求}

如果想控制基於類的數組的記憶體配置,必須實現operator new的數組形式——operator new[]

重寫operator new(和operator new[])時所有要遵循的常規就這些。對於operator delete(以及它的夥伴operator delete[]),情況更簡單。所要記住的只是,c++保證刪除null 指標永遠是安全的,所以你要充分地應用這一保證。下面是非類成員形式的operator delete的虛擬碼:

void operator delete(void *rawmemory){  if (rawmemory == 0) return;    //如果指標為空白,返回                                 //   釋放rawmemory指向的記憶體;  return;}

假設類的operator new將“錯誤”大小的分配請求轉給::operator new,那麼也必須將“錯誤”大小的刪除請求轉給::operator delete:

class base {                       // 和前面一樣,只是這裡聲明了public:                            // operator delete  static void * operator new(size_t size);  static void operator delete(void *rawmemory, size_t size);  ...};void base::operator delete(void *rawmemory, size_t size){  if (rawmemory == 0) return;      // 檢查null 指標  if (size != sizeof(base)) {      // 如果size"錯誤",    ::operator delete(rawmemory);  // 讓標準operator來處理請求    return;                          }  釋放指向rawmemory的記憶體;  return;}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.