I'm using a custom allocator to account for memory usage in several containers. Currently I use a static variable to account for the memory usage. How could I separate this account across several containers without having to rewrite the allocator to use different static variables?
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;
}
Allocators handle all the requests for allocation and deallocation of memory for a given container. The C++ Standard Library provides general-purpose allocators that are used by default, however, custom allocators may also be supplied by the programmer.
Under the hood, the C function std::malloc will typically be used. Therefore, an allocator, who uses preallocated memory can gain a great performance boost. An adjusted allocator also makes a lot of sense, if you need a deterministic timing behavior of your program.
std::allocator is used when you want to separate allocation and do construction in two steps. It is also used when separate destruction and deallocation is done in two steps. All the STL containers in C++ have a type parameter Allocator that is by default std::allocator.
A Merchandise Allocator allocates merchandise to stores according to warehouse and store inventory levels. Will assist stores with merchandise transfers to fulfill stock needs. Being a Merchandise Allocator may require a bachelor's degree. Typically reports to a supervisor or manager.
If you mean that you want a separate counter for each container type, you could simply include the container type as a template parameter and uncomment static size_t allocated
so it's a static member variable. This way, a separate counter variable will be generated for each type of container.
If you're saying you want a separate counter for each instance of a container, you need to make size_t allocated
a non-static member variable. The problem is, you'll also need some kind of hook so you can access the allocation counter from outside each container. The STL allocator design makes it difficult to do this. Some STL containers have a constructor that lets you pass an instance of an allocator, but not all containers support this. On containers that support this, you can include a reference to some global map inside your allocator class, and then pass an instance of your allocator to the constructor of each container. Then, when you call accounting_allocator::allocate()
, the allocator would record the number of bytes it has allocated in the global map. Still, I can't see how you could easily associate this information with a particular container instance, since the allocator object does not know which container it belongs to.
Honestly, if you're just collecting debug info, it's probably easier to just define a non static size_t allocated
, and have accounting_allocator::allocate()
simply output the stats to a file or to stdout. Alternatively, look into using a memory profiler tool for the platform you develop on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With