Source code
#include <memory>
#include <iostream>
#include <vector>
template<typename T>
struct TrackingAllocator : public std::allocator<T>
{
template<typename U> struct rebind
{
typedef TrackingAllocator other;
};
T* allocate(size_t n, const void* hint = 0)
{
T* p = std::allocator<T>::allocate(n, hint);
std::cout << "Allocated " << n * sizeof(T)
<< " bytes at " << p << std::endl;
return p;
}
void deallocate(T* p, size_t n)
{
std::allocator<T>::deallocate(p, n);
std::cout << "Deallocated " << n * sizeof(T)
<< " bytes at " << p << std::endl;
}
};
int main()
{
std::vector<int, TrackingAllocator<int>> vec = {1, 2, 3};
vec.push_back(4);
vec.push_back(5);
vec.push_back(6);
vec.push_back(7);
return 0;
}
$ g++ --version g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609 $ g++ main.cpp -std=c++11 -g
Debugging
$ gdb a.out (gdb) b 32 (gdb) r Allocated 12 bytes at 0x615c20 Breakpoint 1, main () at main.cpp:32 32 vec.push_back(4); (gdb) x/3w 0x615c20 0x615c20: 1 2 3 (gdb) n Allocated 24 bytes at 0x616050 Deallocated 12 bytes at 0x615c20 33 vec.push_back(5); (gdb) x/6w 0x616050 0x616050: 1 2 3 4 0x616060: 0 0 (gdb) n 34 vec.push_back(6); (gdb) x/6w 0x616050 0x616050: 1 2 3 4 0x616060: 5 0 (gdb) n 35 vec.push_back(7); (gdb) x/6w 0x616050 0x616050: 1 2 3 4 0x616060: 5 6 (gdb) n Allocated 48 bytes at 0x616070 Deallocated 24 bytes at 0x616050 36 return 0; (gdb) x/12w 0x616070 0x616070: 1 2 3 4 0x616080: 5 6 7 0 0x616090: 0 0 0 0
Result
As soon as the std::vector runs out of memory its default allocator (std::allocator<T>) allocates a new chunk of memory which provides twice as much memory as the last one and deallocates the old one.