2015-05-27 60 views
2

我想跟蹤由所有STL容器(如map,list,vector等)分配的所有內存(由std lib分配的大小)。我只想跟蹤STL容器而不是定期創建對象。基本上要覆蓋新的和刪除標準庫。如何跟蹤由STL庫分配的內存

class demo { 
public: 
    int i; 
    std::list<int> mylist; 
} 

int main() { 
demo dd = new demo(); // -> Don't want to track this. Just want to track 
         // mylist(size of my list) 
} 

我發現性病有它自己的分配器選項。例如列表中有它分配

template < class T, class Alloc = allocator<T> > class list; 

是什麼,如果我不定義任何默認分配。我有一千個列表,沒有一個有分配器,我不想手動更改它們中的每一個。所以,我在想,如果有辦法,我可以用我的代替默認分配器。

如何做到這一點?

+1

定義跟蹤內存? –

+0

@iharob你能詳細說明一下嗎? – eswaat

+1

我?你必須詳細說明,你想做什麼顯然沒有任何意義。 –

回答

1

標準容器的默認分配器是std::allocator,它在沒有提供分配器時用於所有標準容器(std::vector,std::list等)。

要跟蹤分配和釋放,您將必須創建一個可用於跟蹤的分配器。你可以使用這樣的事情:

template<typename _Ty> 
struct MyAllocator 
{ 
    typedef _Ty value_type; 
    static _Ty* allocate(std::size_t n) 
    {  
     //Code that runs every allocation 
     ... 
     return std::allocator<_Ty>{}.allocate(n); 
    } 

    static void deallocate(_Ty* mem, std::size_t n) 
    { 
     //Code that runs every deallocation 
     ... 
     std::allocator<_Ty>{}.deallocate(mem, n); 
    } 
}; 

MyAllocator鏡子std::allocator,但它可以讓你當分配發生時運行一些自己的代碼。你想放在那裏取決於你。

有兩種方法可以讓所有的容器使用你的分配器。

  1. 您可以替換模板別名std::list(或std::vectorstd::map等)的所有實例。對於std::list別名應該是這樣的:

    template<typename _Ty> 
    using MyList = std::list<_Ty, MyAllocator<_Ty>; 
    

    MyList替換的std::list所有實例。現在你的分配器被所有的容器使用。將此應用到另一個容器將list更改爲容器的名稱(例如,vector將別名重命名爲MyVector並將std::list更改爲std::vector)。

  2. 如果您無法編輯文件或者您不想修改它,還有另一個選項。您可以使用宏將您所定義的類替換list的所有實例。此類必須在namespace std中聲明,並且在設置宏之前必須確保包含<list>。將其設置爲std::list應該是這樣的:

    #include <list> 
    
    namespace std 
    { 
        template<typename _Ty, typename _Alloc = MyAllocator<_Ty>> 
        using tracked_list = list<_Ty, _Alloc>; 
    } 
    
    #define list tracked_list 
    

    對於不同的容器,改變list你要替換(出任何容器vector變化tracked_listtracked_vector在這兩個位置,並在所有vector更換list。三個位置,確保這個代碼在任何其他包含可能使用std::list之前的代碼。如果你把它放在一個頭文件中,在其他任何東西之前加上這個頭。如果它位於源文件中,請將其放在文件的頂部。此代碼不會覆蓋用戶提供的分配器,但它會使分配器成爲默認分配器。

    此方法將更改變量名稱,這可能會影響您的代碼。如果可能的話,你應該使用方法1.但是,如果你有不能更改的代碼或者代碼位於外部頭文件中,並且這也需要應用於此,則此方法應該可以工作。

0

如果你的主要任務是短期內實現成本低(相對於較長期的可維護性),繞過它來包裝你demo類轉換爲包含std命名空間的outer命名空間的一種方式。在outer::std內部,您可以使用自定義分配器重新定義vectorlist等。通過這樣做,所有對std名稱空間的引用將解析爲outer::std。 除了實現自定義分配器外,唯一需要的工作是將所有代碼包裝到外部命名空間中,並在outer::std中提供所有必需的定義。這部分可能很容易變成一種痛苦。未來的貢獻者可能會受苦。

事情是這樣的:

#include <iostream> 
#include <vector> 
namespace outside 
{ 
    template<typename T> 
    struct MyAllocator 
    { 
    typedef typename std::allocator<T>::value_type value_type; 
    typedef typename std::allocator<T>::pointer pointer; 
    typedef typename std::allocator<T>::const_pointer const_pointer; 
    typedef typename std::allocator<T>::reference reference; 
    typedef typename std::allocator<T>::const_reference const_reference; 
    typedef typename std::allocator<T>::size_type size_type; 
    pointer allocate (size_type n, typename std::allocator<void>::const_pointer hint=0) 
    { 
     std::cerr << "allocate..." << std::endl; 
     return std::allocator<T>{}.allocate(n, hint); 
    } 
    void deallocate (pointer p, size_type n) 
    { 
     std::cerr << "deallocate..." << std::endl; 
     return std::allocator<T>{}.deallocate(p, n); 
    } 
    template <class Type> struct rebind 
    { 
     typedef MyAllocator<Type> other; 
    }; 
    MyAllocator() 
    { 
    } 
    MyAllocator(const MyAllocator<T>& other) 
    { 
    } 
    template< class U > 
    MyAllocator(const MyAllocator<U>& other) 
    { 
    } 
}; 
} // namespace outside 

namespace outer 
{ 
namespace std 
{ 
template<class T> 
using vector = ::std::vector<T, outside::MyAllocator<T>>; 
} // namespace std 

class demo 
{ 
public: 
    int i; 
    std::vector<int> myVector; 
}; 
} // namespace outer 

int main() 
{ 
    using outer::demo; 
    std::cerr << "creating new demo" << std::endl; 
    demo *dd = new demo(); 
    std::cerr << "resizing dd->myList" << std::endl; 
    dd->myVector.resize(10,3); 
    delete dd; 
} 
+0

只是想補充一點,gcc和clang的更新版本允許你編寫一個「最小」的分配器,而不需要所有的typedefs和其他語言,儘管它們的實現有點缺陷(比如std :: list) – Alejandro

+0

你錯過了一個花括號來完成外部命名空間。 – eswaat

+0

我創建了同樣的東西,但不知何故,它不工作模板 使用deque = :: std :: deque >; – eswaat