2011-07-22 76 views
8

我決定在我的類中重載新的[],...操作符,這樣我就可以記錄它們被調用的文件和行,以便更輕鬆地跟蹤內存分配/泄漏。重載新的操作員問題

現在的問題是在我的堆棧和數組類(和其他模板容器類,其中分配內存):

如果我和我的一個類具有使用這些新的,新的[],...運算符超載它工作正常。因爲沒有重載的新操作符匹配新的參數(__ LINE __,__ FILE __),所以我不能分配它們,所以我不能分配它們。 )運營商(或其他類似新的投放)。堆代碼

例子:

// placement new 
T* t=new(__ LINE __ , __ FILE__)(&m_data[i])T; 

所以我出如何使這項工作很好的想法。如果我用新的鬆散內存記錄功能替換新的(__ LINE __,__ FILE __)。 一種解決方案是爲標準數據類型製作一個單獨的堆棧,其中使用默認的新數據類型。

有什麼辦法可以在編譯時檢測模板參數是結構體,類還是內建的C++類型?

你如何處理這樣的東西? 你有什麼建議? 對此設計的任何評論(好的,壞的)顯然是受歡迎的(只是不要發佈像「不要用自己的容器重新發明輪子」之類的東西)。

+1

你有沒有超載' operator new(__ LINE__,__FILE __)',並試圖與'int','float'等一起使用? – iammilind

+0

一個選擇是替換全局的'operator new()'和朋友。 – sharptooth

+5

如果你正在調試內存泄漏,我不明白你爲什麼要做一些已經存在的工作:Valgrind? – Nim

回答

0
struct Int { 
    int i; 
    Int (int _i) : i(_i) {} 
    operator int() const {return i;} 
}; 

#define __LINE_NUMBER__ Int(__LINE__) 

使用這個宏而不是標準的行號宏觀和重載決議將從其他int號碼區分Int行號。

我無法想象這將如何完整工作。你打算使用它像int * x = NEW(int,123);或類似的東西?

順便說一句,我同意評論者 - 你可能不必走這條路。超載new是一種黑色藝術,通常應避免。

+0

我不認爲你明白我想要什麼:__LINE__宏沒有問題。或者你想告訴我其他什麼? – n3XusSLO

+0

問題是'__LINE__'產生一個干擾重載分辨率的int,對吧?在這裏,我將它包裝在一個類中,以便重載是不同的。 – spraff

0

有什麼辦法可以在編譯時檢測模板參數是一個struct,class還是 內置的C++類型?

您可以使用噓:: type_traits和boost :: mpl它。

例子:

#include <boost/type_traits.hpp> 
#include <boost/mpl/not.hpp> 
#include <boost/mpl/logical.hpp> 

template <class T> 
typename boost::enable_if<boost::is_class<T>, T>::type 
foo(){cout << "is class " << endl;}; 

template <class T> 
typename boost::enable_if<boost::mpl::not_<boost::is_class<T> >, T>::type 
foo(){cout << "is not class "<< endl;}; 

類型列表 - http://www.boost.org/doc/libs/1_47_0/libs/type_traits/doc/html/index.html

或者你可以使用boost :: MPL ::爲您設置的類型設置

+0

我仍然試圖圍繞這個東西包裝我的頭:在模板類中,我可以讓編譯器選擇使用默認的新的或重載的新的基於模板參數類型的編譯時(如果它是一個結構或類會選擇重載新的,但如果它是其他任何東西,它會選擇默認的新?) – n3XusSLO

1

請注意,目前的解決方案需要增加日誌代碼爲,每new(line, file)超載。此外,除非您在#ifndef DEBUG ... #endif之內圍繞每個日誌記錄調用,否則無法在發佈版本中將其輕鬆切換。

下面是實現的一個方式,你wnat什麼:除了重載new運營商爲每個類的,考慮超載使用位置語法全球new操作;這樣可以避免干擾'正常'運營商。然後,您可以爲0123.htm #define新宏和刪除宏,更重要的是,您可以控制何時應用內存跟蹤new/delete以及何時使用標準版本。

#ifdef ENABLE_CUSTOM_ALLOC 

// Custom new operator. Do your memory logging here. 
void* operator new (size_t size, char* file, unsigned int line) 
{ 
    void* x = malloc(size); 
    cout << "Allocated " << size << " byte(s) at address " << x 
     << " in " << file << ":" << line << endl; 
    return x; 
} 

// You must override the default delete operator to detect all deallocations 
void operator delete (void* p) 
{ 
    free(p); 
    cout << "Freed memory at address " << p << endl; 
} 

// You also should provide an overload with the same arguments as your 
// placement new. This would be called in case the constructor of the 
// created object would throw. 
void operator delete (void* p, char* file, unsigned int line) 
{ 
    free(p); 
    cout << "Freed memory at address " << p << endl; 
} 

#define new new(__FILE__, __LINE__) 

#endif 


// A test class with constructors and destructor 
class X 
{ 
public: 
    X() { cout << "X::ctor()" << endl; } 
    X(int x) { cout << "X::ctor(" << x << ")" << endl; } 
    ~X() { cout << "X::dtor()" << endl; } 
}; 


int main (int argc, char* argv[]) 
{ 
    X* x3 = new X(); 
    X* x4 = new X(20); 
    delete x3; 
    delete x4; 
} 

你應該看到:

Allocated 1 byte(s) at address 00345008 in Alloc.cpp:58 
X::ctor() 
Allocated 1 byte(s) at address 003450B0 in Alloc.cpp:59 
X::ctor(20) 
X::dtor() 
Freed memory at address 00345008 
X::dtor() 
Freed memory at address 003450B0 

嘗試替代Xint,你會看到它也能工作。你可以將它擴展到新的數組和位置,但是我寧願不讓帖子比它長。在結束

最後幾個指針:
- MSVC具有此功能,請參閱here
- 有一個toturial關於做內存下的「跟蹤內存泄露」部分跟蹤這樣here