程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Item 50:為什麼需要自定義new和delete?

Item 50:為什麼需要自定義new和delete?

編輯:C++入門知識

Item 50:為什麼需要自定義new和delete?


Item 50: Understand when it makes sense to replace new and delete.

我們在Item 49中介紹了如何自定義new的錯誤處理函數,以及如何為你的類重載operator new。 現在我們回到更基礎的問題,為什麼我們需要自定義operator newoperator delete

  • 檢測使用錯誤。new得到的內存如果沒有delete會導致內存洩露,而多次delete又會引發未定義行為。如果自定義operator new來保存動態內存的地址列表,在delete中判斷內存是否完整,便可以識別使用錯誤,避免程序崩潰的同時還可以記錄這些錯誤使用的日志。
  • 提高效率。全局的newdelete被設計為通用目的(general purpose)的使用方式,通過提供自定義的new,我們可以手動維護更適合應用場景的存儲策略。
  • 收集使用信息。在繼續自定義new之前,你可能需要先自定義一個new來收集地址分配信息,比如動態內存塊大小是怎樣分布的?分配和回收是先進先出FIFO還是後進先出LIFO?
  • 實現非常規的行為。比如考慮到安全,operator new把新申請的內存全部初始化為0.
  • 其他原因,比如抵消平台相關的字節對齊,將相關的對象放在一起等等。

    自定義一個operator new很容易的,比如實現一個支持越界檢查的new

    static const int signature = 0xDEADBEEF;    // 邊界符
    typedef unsigned char Byte; 
    
    void* operator new(std::size_t size) throw(std::bad_alloc) {
        // 多申請一些內存來存放占位符 
        size_t realSize = size + 2 * sizeof(int); 
    
        // 申請內存
        void *pMem = malloc(realSize);
        if (!pMem) throw bad_alloc(); 
    
        // 寫入邊界符
        *(reinterpret_cast(static_cast(pMem)+realSize-sizeof(int))) 
            = *(static_cast(pMem)) = signature;
    
        // 返回真正的內存區域
        return static_cast(pMem) + sizeof(int);
    }
    

    其實上述代碼是有一些瑕疵的:

    • Item 49提到operator new應當不斷地調用new handler,上述代碼中沒有遵循這個慣例;
    • 有些體系結構下,不同的類型被要求放在對應的內存位置。比如double的起始地址應當是8的整數倍,int的起始地址應當是4的整數倍。上述代碼可能會引起運行時硬件錯誤。
    • 起始地址對齊。C++要求動態內存的起始地址對所有類型都是字節對齊的,newmalloc都遵循這一點,然而我們返回的地址偏移了一個int

      到此為止你已經看到了,實現一個operator new很容易,但實現一個好的operator new卻很難。其實我們還有別的選擇:比如去讀編譯器文檔、內存管理的商業工具、開源內存管理工具等。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved