// clang++ -std=c++11 -o stlsizeof stlsizeof.cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint64_t memory_usage; // use this when calling STL object if you want // to keep track of memory usage template class MemoryCountingAllocator { 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; // rebind allocator to type U template struct rebind { typedef MemoryCountingAllocator other; }; pointer address(reference value) const { return &value; } const_pointer address(const_reference value) const { return &value; } MemoryCountingAllocator() : base() {} MemoryCountingAllocator(const MemoryCountingAllocator &) : base() {} template MemoryCountingAllocator(const MemoryCountingAllocator &) : base() {} ~MemoryCountingAllocator() {} // return maximum number of elements that can be allocated size_type max_size() const throw() { return base.max_size(); } pointer allocate(size_type num, const void * p = 0) { memory_usage += num * sizeof(T); return base.allocate(num,p); } void construct(pointer p, const T &value) { return base.construct(p,value); } // destroy elements of initialized storage p void destroy(pointer p) { base.destroy(p); } // deallocate storage p of deleted elements void deallocate(pointer p, size_type num ) { memory_usage -= num * sizeof(T); base.deallocate(p,num); } std::allocator base; }; // for our purposes, we don't want to distinguish between allocators. template bool operator==(const MemoryCountingAllocator &, const T2 &) throw() { return true; } template bool operator!=(const MemoryCountingAllocator &, const T2 &) throw() { return false; } void initializeMemUsageCounter() { memory_usage = 0; } uint64_t getMemUsageInBytes() { return memory_usage; } typedef std::set,MemoryCountingAllocator > treeset; typedef std::unordered_set,std::equal_to,MemoryCountingAllocator > hashset; typedef std::vector > vector; typedef std::list > list; typedef std::deque > deque; int main() { size_t N = 1024; std::cout << "Displaying memory usage in bytes."< : " << getMemUsageInBytes() * 1.0 / N << std::endl; initializeMemUsageCounter(); assert(getMemUsageInBytes() == 0); list l; for(uint32_t k = 0; k < N; k++) l.push_back(k); std::cout << "memory usage per element of a list : " << getMemUsageInBytes() * 1.0 / N << std::endl; initializeMemUsageCounter(); assert(getMemUsageInBytes() == 0); deque dq; for(uint32_t k = 0; k < N; k++) dq.push_back(k); std::cout << "memory usage per element of a deque : " << getMemUsageInBytes() * 1.0 / N << std::endl; initializeMemUsageCounter(); assert(getMemUsageInBytes() == 0); hashset h; for(uint32_t k = 0; k < N; k++) h.insert(k); std::cout << "memory usage per element of an unordered_set : " << getMemUsageInBytes() * 1.0 / N << std::endl; initializeMemUsageCounter(); assert(getMemUsageInBytes() == 0); treeset t; for(uint32_t k = 0; k < N; k++) t.insert(k); std::cout << "memory usage per element of a set : " << getMemUsageInBytes() * 1.0 / N << std::endl; std::cout << "Comments : " << std::endl; std::cout << "This is an optimistic estimate: the overhead of the data structure and the allocations is ignored." << std::endl; std::cout << "Because the per-value overhead might be fixed, the results might be less dramatic with larger elements, such as long strings." << std::endl; }