1. 程式人生 > >C++進階--解謎operator new/delete

C++進階--解謎operator new/delete

//############################################################################
// 解謎operator new/delete

/* 執行下面程式碼會發生什麼? 
 */

   dog* pd = new dog();
/* 
 * Step 1. 呼叫operator new分配記憶體
 * Step 2. 呼叫建構函式構造dog
 * Step 3. 如果第2部拋異常,呼叫operator delete釋放第1步分配的記憶體 
 */
   delete pd;
/* 
 * Step 1. 呼叫dog的解構函式
 * Step 2. 呼叫operator delete釋放記憶體
 */


/*
 * 自己實現operator new:
 *
 * 注意: new handler是當operator new分配記憶體失敗時呼叫的函式
 *   set_new_handler()函式設定一個新的new handler並且返回當前的new handler
 */
void* operator new(std::size_t size) throw(std::bad_alloc) {
   while (true) {
      void* pMem = malloc(size);   // 分配記憶體
      if (pMem) 
         return pMem;              // 成功則返回指標

      std::new_handler Handler = std::set_new_handler(0);  // 獲取當前的new handler
      std::set_new_handler(Handler);  //寫回

      if (Handler)
         (*Handler)();            // 呼叫new handler
      else
         throw bad_alloc();       // 如果new handler為空, 拋異常
   }
}


/* 
 * 成員函式中的Operator new
 */
class dog {
   ...
   public:
   static void* operator new(std::size_t size) throw(std::bad_alloc) 
   {
//      if (size == sizeof(dog))
         customNewForDog(size);
 //     else
//         ::operator new(size);
   }
   ...
};

class yellowdog : public dog {
   int age;
   static void* operator new(std::size_t size) throw(std::bad_alloc) 
};

int main() {
   yellowdog* py= new yellowdog();   //呼叫了dog的operator new
}

/*
* 解決方法 1:
*     if (size == sizeof(dog))  //加判斷
*        customNewForDog();
*     else
*        return ::operator new(size);
*
* 解決方法 2:
*     yellowdog也過載operator new
*/



/* operator delete也是類似 */
class dog {
   static void operator delete(void* pMemory) throw() {  //
      cout << "Bo is deleting a dog, \n";
      customDeleteForDog();
      free(pMemory);
   }
//   virtual ~dog() {};   
};

class yellowdog : public dog {
   static void operator delete(void* pMemory) throw() {
      cout << "Bo is deleting a yellowdog, \n";
      customDeleteForYellowDog();
      free(pMemory);
   }
};

int main() {
   dog* pd = new yellowdog();
   delete pd;   //呼叫了dog的operator delete
}

// 如何解決?
// operator delete定義成虛擬函式?
// 不行!不能既是靜態函式(物件無關)又是虛擬函式(物件相關)
//
//
// 解決方法:
//   virtual ~dog() {}
// 為什麼加個虛解構函式就ok?
// 先調析構(多型),再釋放記憶體





/*
 * 為什麼要自定義new/delete
 *
 * 1. 使用錯誤檢測: 
 *    - 記憶體洩漏檢測/垃圾回收. 
 *    - 陣列的索引超出範圍,在記憶體的首尾做簽名,就可以檢測陣列越界
 * 2. 提升效率:
 *    a. 將相關物件聚類,減少頁錯誤(不命中)
 *    b. 固定大小分配(適合很多小物件的應用)
 *    c. 將相似尺寸的物件排到同一位置以減小碎片
 * 3. 執行額外的任務:
 *    a. 將去分配的記憶體清0--安全性.
 *    b. 收集使用統計
 */

/*
 * 寫一個好的記憶體管理器很難!
 *
 * 在寫自己版本的之前, 考慮:
 *
 * 1. 根據你的需要調教下你的編譯器;
 * 2. 搜尋記憶體管理庫, 例如boost中的pool庫
 */