2015-05-27 1 views
2

Я хочу отслеживать всю память (размер выделен std lib), выделенный всеми контейнерами STL, такими как map, list, vector и т. Д. Я просто хочу отслеживать создание STL-контейнера, а не создание обычного объекта. В основном хотите переопределить новые и удалить std lib.Как отслеживать назначение памяти библиотекой 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::vector, std::map и т.д.) с шаблоном псевдонима. Для std::list псевдоним будет выглядеть следующим образом:

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

    Заменить все экземпляры std::list с MyList. Теперь ваш распределитель используется всеми вашими контейнерами. Чтобы применить это к другому изменению контейнера 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 в любой контейнере вы хотите заменить (Ex для vector изменений tracked_list к tracked_vector в обоих местах и ​​заменить list с vector во всем. в трех местах. Убедитесь, что этот код до того, как все остальные могут использовать std::list. Если вы поместите его в файл заголовка, включите этот заголовок перед чем-либо еще.Если он находится в исходном файле, поместите его в верхнюю часть файла. Этот код не будет отменять назначенные пользователем распределители, но он сделает ваш распределитель распределителем по умолчанию.

    Этот метод изменяет имена переменных и может повлиять на ваш код. Если возможно, вы должны использовать метод 1. Однако, если у вас есть код, который вы не можете изменить или код, который находится во внешних заголовках, и это тоже нужно применить к этому, этот метод должен работать.

0

Если ваш главный приоритет краткосрочной перспективы низкой стоимость реализации (в отличие от более долгосрочной ремонтопригодности), один из способов обойти это, чтобы обернуть demo класс в outer пространства имен, которое содержит std пространства имен. Внутри outer::std вы можете переопределить vector, list и т. Д. С вашим пользовательским распределителем. Таким образом, все ссылки на пространство имен 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, но как-то не работает шаблон using deque = :: std :: deque >; – eswaat

Смежные вопросы