2009-10-27 2 views
4

Я использую собственный распределитель для учета использования памяти в нескольких контейнерах. В настоящее время я использую статическую переменную для учета использования памяти. Как я могу отделить эту учетную запись в нескольких контейнерах, не переписывая распределитель для использования разных статических переменных?Использование памяти учетной записи с помощью пользовательского распределителя


static size_t allocated = 0; 


    template <class T> 
    class accounting_allocator { 
    public: 
     // type definitions 
     typedef T  value_type; 
     typedef T*  pointer; 
     typedef const T* const_pointer; 
     typedef T&  reference; 
     typedef const T& const_reference; 
     typedef std::size_t size_type; 
     typedef std::ptrdiff_t difference_type; 
     //static size_t allocated; 

     // rebind allocator to type U 
     template <class U> 
     struct rebind { 
      typedef accounting_allocator<U> other; 
     }; 

     // return address of values 
     pointer address (reference value) const { 
      return &value; 
     } 
     const_pointer address (const_reference value) const { 
      return &value; 
     } 

     /* constructors and destructor 
     * - nothing to do because the allocator has no state 
     */ 
     accounting_allocator() throw() { 
     } 
     accounting_allocator(const accounting_allocator&) throw() { 
     } 
     template <class U> 
     accounting_allocator (const accounting_allocator<U>&) throw() { 
     } 
     ~accounting_allocator() throw() { 
     } 

     // return maximum number of elements that can be allocated 
     size_type max_size() const throw() { 
     // std::cout << "max_size()" << std::endl; 
      return std::numeric_limits<std::size_t>::max()/sizeof(T); 
     } 

     // allocate but don't initialize num elements of type T 
     pointer allocate (size_type num, const void* = 0) { 
      // print message and allocate memory with global new 
      //std::cerr << "allocate " << num << " element(s)" << " of size " << sizeof(T) << std::endl; 
      pointer ret = (pointer)(::operator new(num*sizeof(T))); 
      //std::cerr << " allocated at: " << (void*)ret << std::endl; 
      allocated += num * sizeof(T); 
      //std::cerr << "allocated: " << allocated/(1024*1024) << " MB" << endl; 
      return ret; 
     } 

     // initialize elements of allocated storage p with value value 
     void construct (pointer p, const T& value) { 
      // initialize memory with placement new 
      new((void*)p)T(value); 
     } 

     // destroy elements of initialized storage p 
     void destroy (pointer p) { 
      // destroy objects by calling their destructor 
      p->~T(); 
     } 

     // deallocate storage p of deleted elements 
     void deallocate (pointer p, size_type num) { 
      // print message and deallocate memory with global delete 
#if 0 
      std::cerr << "deallocate " << num << " element(s)" 
        << " of size " << sizeof(T) 
        << " at: " << (void*)p << std::endl; 
#endif 
      ::operator delete((void*)p); 
      allocated -= num * sizeof(T); 
     } 
    }; 
    template<> 
    class accounting_allocator<void> 
    { 
    public: 
     typedef size_t  size_type; 
     typedef ptrdiff_t difference_type; 
     typedef void*  pointer; 
     typedef const void* const_pointer; 
     typedef void  value_type; 

     template<typename _Tp1> 
     struct rebind 
     { typedef allocator<_Tp1> other; }; 
    }; 


    // return that all specializations of this allocator are interchangeable 
    template <class T1, class T2> 
    bool operator== (const accounting_allocator<T1>&, 
        const accounting_allocator<T2>&) throw() { 
     return true; 
    } 
    template <class T1, class T2> 
    bool operator!= (const accounting_allocator<T1>&, 
        const accounting_allocator<T2>&) throw() { 
     return false; 
    } 
+0

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

+0

Я хотел иметь учетную запись для каждого контейнера, который использует этот распределитель. Я думал о создании нескольких классов со статическим выделенным членом счета, но я не уверен, могу ли я передать этот класс в качестве параметра шаблона в распределитель, без сбоев, когда он пытается перепрофилировать и т. Д., Который использует только один параметр шаблона. – piotr

ответ

0

Поместите декларацию "статического size_t выделяемого" в классе defininition. У каждой шаблонной копии будет отдельный счетчик, общий для всех объектов этого шаблона.

6

Если вы имеете в виду, что для каждого типа контейнера требуется отдельный счетчик, вы можете просто указать тип контейнера в качестве параметра шаблона и раскомментировать static size_t allocated, так что это статическая переменная-член. Таким образом, для каждого типа контейнера будет создана отдельная переменная счетчика.

Если вы хотите сказать, что вы хотите отдельный счетчика для каждого экземпляра контейнера, вам нужно сделать size_t allocated нестатическим переменный член. Проблема в том, что вам также понадобится какой-то крючок, чтобы вы могли получить доступ к счетчику распределения извне каждого контейнера. Конструкция распределителя STL затрудняет это. В некоторых контейнерах STL есть конструктор, который позволяет передавать экземпляр распределителя, но не все контейнеры поддерживают это. В контейнерах, которые поддерживают это, вы можете включить ссылку на некоторую глобальную карту внутри вашего класса распределителя, а затем передать экземпляр вашего распределителя в конструктор каждого контейнера. Затем, когда вы вызываете accounting_allocator::allocate(), распределитель будет записывать количество байтов, которое он выделил на глобальной карте. Тем не менее, я не вижу, как вы могли бы легко связать эту информацию с конкретным экземпляром контейнера, поскольку объект-распределитель не знает, к какому контейнеру он принадлежит.

Честно говоря, если вы просто собираете информацию об отладке, возможно, просто определить нестационарный size_t allocated и получить accounting_allocator::allocate() просто вывод статистики в файл или на стандартный вывод. Кроме того, изучите использование инструмента профилирования памяти для платформы, на которой вы разрабатываете.

0

Смотрите мои примеры кода:

// uintptr_t represents an object address 
// as a numerical value. 
// you could use unsigned long insead if 
// sizeof(long) == sizeof(void*) on your system. 
struct AllocCounter { 
    static size_t *Register(uintptr_t uContainer) 
    { 
     // insert container address into map, and 
     // return an associated allocation counter. 
    } 
    static bool Unregister(uintptr_t uContainer) 
    { 
     // remove container address and the 
     // associated allocation counter from the map 
    } 
    static void DebugCounter(void) 
    { 
     // statistic of all container objects. 
    } 
protected: 
    static hash_map<uintptr_t, size_t> m_aCounter; 
}; 

Кроме того, вы можете связать имя контейнера или объект класса т.д., со счетчиком выделения путем усиления выше AllocCounter.

И пример контейнера:

class Container 
{ 
public: 
    Container(void) 
    { 
     m_pAllocCounter = AllocCounter::Register((uintptr_t)this); 
     .... 
    } 
    ~Container() 
    { 
     AllocCounter::Unregister((uintptr_t)this); 
    } 
    pointer ObjectAllocate(void) 
    { 
     pointer obj; 
     *m_pAllocCounter += sizeof *obj; 
     obj = new CObject; 
     return obj; 
    } 
    void ObjectDealloc(pointer pObj) 
    { 
     *m_pAllocCounter -= sizeof *pObj; 
     delete pObj; 
    } 
    .... 

private: 
    size_t *m_pAllocCounter; 
    .... 
}; 

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

  • Нет связанных вопросов^_^