c++ 中的重載全域new,delete

來源:互聯網
上載者:User

最近做一個小項目,對c++又有很多新的理解。實在不的不讓人發出感歎,c++太強大了,絕對不是一朝一夕就可以領悟她的內涵的。

       首先我們要清楚,為什麼我們要重載new,和delete了?這還不是指標造成的,確實指標是一件讓人喜歡的東西,用起來如此讓人喜歡,讓人順手。然而小程式我們完全可以避免記憶體泄露問題,大程式就不那麼容易了,然而我們有一種特別好的方法可以跟蹤我們new,和delete動作,找到未被釋放的記憶體。辦法是什麼呢?微軟給我們提供了一種很好的方法,那就是重載new,和delete。

       在實現之前我們要清楚new,和delete的工作機理,這是個多麼好的學習機會啊!

       對與new操作符,其實和sizeof一樣,都是c++內建的,然而像strlen就不是了,strlen屬於函數。對於new的功能我們是沒有辦法改變的,當我們new一個對象時,new為我們做了兩件事情,一、申請一塊足夠的記憶體空間供存放對象,對於new一個數組對象,編譯器會計算出總共的空間,然後執行類似c語言中malloc函數類似的功能。二、初始化對象,對於單個對象,包括包括基本對象和類對象,可以通過括弧初始化,比如int * pn = new int(3); A * pa = new A(3);   然而對於數組不能初始化,對於類對象,必須定義無參數的建構函式。對與new的準系統我們是無法改變的。

       我們所能改變的就是如何為對象分配記憶體,我們可一重載這個函數以實現分配記憶體。通常的重載方式是:

       void * operator new (size_t size);

       然而這已經足夠了,在一般的operator new 重載函數裡,我們可以再加入其它參數,但第一個參數必須是size_t類型,即為無符號整形。正是有這種特性,為我們對記憶體申請和釋放的跟蹤提供了可能。

       具體實現就是第一個operator new 的重載函數,我們第一的這個函數是這樣的:

void * operator new(unsigned int size, const char *file, int line)
{
    cout << "new size:" << size << endl;
    cout << file << " " << line << endl;

    void * p = malloc(size);

    return p;
}

然後用宏替換所有的new:

#define new new(__FILE__, __LINE__)

       這樣我們每次調用new,比如int * pn = new int;被編譯器替換成了int * pn = new (__FILE__, __LINE__) int,從而調用我們定義的operator new,這種辦法確實很妙。需要交代的是,對於數組同樣適用,而是在編譯的是後由編譯器計算出所需要的長度調用我們定義的operator new函數。

       對於delete,我們無需使用宏定義,只要重載operator delete就可以了,然而我們需要重載兩個delete:

void operator delete(void * p)
{
    cout << "delete " << (int)p << endl;
    free(p);
}

void operator delete [] (void * p)
{
    cout << "delete [] " << (int)p << endl;
    free(p);
}

       其實後面一個函數的內容和前面的內容一樣,但為了支援數組的釋放,我們必須是要定義的。那麼我們只是簡單的free(p)編譯器咋知道我們釋放的數組,還是單個對象了,這個不用我們操心了,我們只要提供給free函數一個申請記憶體的首地址就可以了。因為在用malloc申請的時候,我們也把數組裝換為記憶體大小了。

       由此我們可以得出下面的推斷:用int * pn = new int [100];的空間,用delete pn釋放和delete [] pn釋放效果一樣。然而那麼既然這兩種方式一樣,那還要delete [] 幹什麼,其實delete [] 有另外的作用就是類對象數組的釋放,編譯器把delete []解釋為調用對象的解構函式,這個是通過迴圈實現的,最後釋放掉申請的記憶體。

       既然我們已經跟蹤了new和delete,那麼就可以比較容易的判斷申請的記憶體是否最後得到釋放,要完成它,我們還需要一個鏈表,或者其它,當我們申請一塊記憶體的時候加入到鏈表中,釋放一塊空間的時候,從鏈表中刪除和釋放記憶體首地址相同的節點就可以了,最後理想的情況是鏈表為空白,如果不為空白,那就說明記憶體發生泄露(Memory leaks)了。

完整代碼:

#include "malloc.h"
#include "iostream.h"

#ifdef _DEBUG

void * operator new(unsigned int size, const char *file, int line)
{
    cout << "new size:" << size << endl;
    cout << file << " " << line << endl;

    // 下面兩種方法可以達到同樣的效果,但下面一種比較好
    // 因為用下面一種可以保持原有的申請方式一樣
    //void * p = malloc(size);
    void * p = operator new(size);

    return p;
}

void operator delete(void * p)
{
    cout << "delete " << (int)p << endl;
    free(p);
}

void operator delete [] (void * p)
{
    cout << "delete [] " << (int)p << endl;
    free(p);
}

void operator delete(void * p, const char *file, int line)
{
    cout << "delete file line" << endl;
    free(p);
}

void operator delete [] (void * p, const char *file, int line)
{
    cout << "delete [] file line" << endl;
    free(p);
}

#define new new(__FILE__, __LINE__)
#endif

void main()
{
    int * p = new int[5];   
    delete [] p;
// delete p;
}

 

from http://blog.sina.com.cn/s/blog_3f56d7800100i1uf.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.