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.