C++ 重載 new 和 delete

經過重載 new 和 delete, 從而控制內存分配的過程.
執行 new 的過程: 
編譯器調用名爲operator new(或operator new[])的標準庫函數, 非配一塊足夠大, 原始, 未命名的內存空間.
編譯器運行相應構造函數, 並未其傳入初始值.
返回一個指向該對象的指針.
執行 delete 的過程: 
先執行相應的析構函數.
編譯器調用名爲operator delete(或operator delete[])的標準庫函數釋放內存空間.
編譯器查找 new 和 delete 的順序: 
若操做對象是類類型, 則編譯器首先在類或基類的做用域中查找. 若類中含 operator new (或 operator delete) 成員, 則調用這些成員.
編譯器在全局做用域中查找匹配的函數, 如有自定義版本, 則使用.
若沒找到, 則使用標準庫定義的版本.
可使用::(做用域運算符)忽略定義在類中的 new 或 delete 函數. eg: ::new只在全局做用域中查找.
new 和 new[]. 使用如下示例說明: 
new int 編譯器解釋爲 new(sizeof(int)).
new int[10] 編譯器解釋爲 new(sizeof(int) * 10).
new 和 operator new 函數的區別 (delete 和 operator delete 相似): 
new 除了調用 operator new 函數, 還要調用構造函數.
咱們日常說的重載 new, 其實只是重載 operator new 函數. 咱們沒法阻止以後調用構造函數的行爲(也不必阻止).
重載
咱們能夠在類中, 或是在全局做用域中定義本身版本的 operator new 和 operator delete.
當在類中定義 operator new 和 operator delete 時, 他們是隱式靜態 的(也就是說, 無需顯式聲明 static, 不過最好仍是聲明吧, 保持統一性). 爲何是靜態的呢? 由於 operator new 用於對象構造前, operator delete 用於析構後. 並且既然是靜態的, 也就沒法操做類的非靜態數據成員了.
operator new 和 operator delete
可定義其餘類型的 operator new.
void *operator new(size_t, void*); 該形式只供標準庫使用, 不容許被用戶重載.
void *operator new(size_t size) {
    if (void *mem = malloc(size)) {
        return mem;
    } else {
        throw bad_alloc();
    }
}html

void operator delete(void mem) noexcept {
    free(mem);
}
1
2
3
4
5
6
7
8
9
10
11
內存泄漏檢測
資料
http://www.cnblogs.com/pangxiaodong/archive/2011/08/29/2158136.html
實現
MemInfoNode 用於記錄申請的一塊內存的信息. MemList 爲一個單項鍊表, 存儲每一個申請的內存塊的數據.
#define new new(__FILE__, __LINE__) 的做用是, 能夠在代碼中直接方便的使用 new, 不改變原來代碼中的語法. eg: new int將替換爲new(__FILE__, __LINE__) int. 編譯器最後將調用 operator new(sizeof(int), __FILE__, __LINE__)函數.
在 MemList 中要使用 malloc 和 free. 防止使用 new, delete 形成的遞歸死循環.
#include <iostream>
using namespace std;node

class MemInfoNode {
private:
    void *pMem = NULL;    //memory address
    size_t memSize = 0;   
    const char *codeFile = NULL;
    unsigned int codeLine = 0;
    MemInfoNode *pNext = NULL;    //point to next nodeios

    void Print(ostream &out = std::cout) {
        out << " FileName: " << codeFile
            << " LineNum: " << codeLine
            << " MemAddr: " << pMem
            << " MemSize: " << memSize
            << std::endl;
    }函數

    friend class MemList;
};spa

class MemList {
public:
    MemList() {}
    ~MemList() {
        MemInfoNode *nTmp = NULL;
        //釋放泄露內存
        while (m_pHeadNode) {
            if (m_pHeadNode->pMem) { 
                free(m_pHeadNode->pMem); 
            }
            // move to next node
            nTmp = m_pHeadNode->pNext;
            free(m_pHeadNode);
            m_pHeadNode = nTmp->pNext;
        }
    }.net

    bool Prepend(void *pMem, size_t memSize, const char *fileName, unsigned int lineNo) {
        if (!pMem) {
            return false;
        }
        MemInfoNode *pNode = (MemInfoNode*)malloc(sizeof(MemInfoNode));
        pNode->pMem = pMem; pNode->memSize = memSize; pNode->codeFile = fileName; pNode->codeLine = lineNo;
        pNode->pNext = m_pHeadNode; m_pHeadNode = pNode;
        return true;
    }指針

    bool Remove(void *ptr) {
        if (!ptr) {
            return false;
        }code

        MemInfoNode *n_pIt = m_pHeadNode;
        MemInfoNode *n_pPtr = NULL;
        while (n_pIt) {
            if (n_pIt->pMem == ptr) {    //findIt
                // 從 list 中 remove node
                if (!n_pPtr) {
                    m_pHeadNode = n_pIt->pNext;
                }
                else {
                    n_pPtr->pNext = n_pIt->pNext;
                }htm

                // free node
                free(n_pIt);
                return true;
            }
            n_pPtr = n_pIt;
            n_pIt = n_pIt->pNext;
        }
        return false;
    }對象

    friend ostream & operator << (ostream &out, MemList obj);

    void Result(ostream &out = std::cout) {
        if (!m_pHeadNode) {
            out << "[OK] This Application no memory leak!" << std::endl;
        }
        else {
            out << "[ERR] This Application have memory leak!" << std::endl;
            MemInfoNode *n_pIt = m_pHeadNode;
            while (n_pIt) {
                n_pIt->Print(out);
                n_pIt = n_pIt->pNext;
            }
        }
    }

private:
    MemInfoNode *m_pHeadNode = NULL;
};

ostream & operator << (ostream &out, MemList obj) {
    obj.Result(out);
    return out;
}

/*---------------  全局變量 ------------------*/
MemList mem_list; 

/*-------------- 重載 new new[] delete delete[] ---------------*/
void *operator new(size_t size, const char *fileName, unsigned int lineNo){
    void *pMem = malloc(size);
    if (pMem) {
        mem_list.Prepend(pMem, size, fileName, lineNo);
    }
    return pMem;
}
void *operator new[](size_t size, const char *fileName, unsigned int lineNo){
    return operator new(size, fileName, lineNo);    //Tips: 不能用 new, 而應該用 operator new
}

void operator delete(void *pMem) {
    if (pMem) {
        free(pMem);
        mem_list.Remove(pMem);
    }
}
void operator delete[](void *pMem) {
    operator delete(pMem);
}


/*------------------ 將 new 替換爲重載的 new ----------------*/
#define new new(__FILE__, __LINE__)


void Test_bad_code() {
    int *p1 = new int;
    int *p2 = new int;
    int *p3 = new int[10];
    int *p4 = new int[20];

    delete p1;
    delete []p3;
}
void Test_good_code() {
    int *p1 = new int;
    int *p2 = new int;
    int *p3 = new int[10];
    int *p4 = new int[20];

    delete p1;
    delete p2;
    delete []p3;
    delete []p4;
}


int main()
{
    Test_good_code();
    Test_bad_code();

    //cout << mem_list;     mem_list.Result();

相關文章
相關標籤/搜索