That is not specified in the standard, new may call malloc or not. In practice in the implementations I have worked with, it does.
The best way to do what you want is to define your own new operator that accounts for allocated memory, or use an accounting allocator for STL containers like this one:
#include <memory> #include <limits> extern size_t allocated; 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); } }; #if 0 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; }; }; #endif // 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; } /************** accounting allocator end ***********/
An example of accounting with new: Although I'd prefer using (3) malloc_hook and an unordered_map
size_t used_mem = 0; std::map<void*,size_t> acc; void* operator new(size_t size) throw (std::bad_alloc) { void *mem; if(size == 0) size = 1; mem = malloc(size); if(mem) { memset(mem, 0, size); used_mem += size; acc[mem] = size; return mem; } std::new_handler nh = std::set_new_handler(0); std::set_new_handler(nh); if (nh) { (*nh)(); return (void*)0; } else { //return (void*)0; throw std::bad_alloc(); } } void operator delete(void *mem) throw() { std::map<void*,size_t>::iterator i = acc.find(mem); if( i != acc.end() ) { size_t size = i->second; used_mem -= size; } free(mem); }