Search code examples
c++stringvisual-c++allocation

std::string allocate memory 2 times for 1 string


#include <iostream>
#include <string>

void* operator new(size_t size) {
    std::cout << "Allocated: " << size << " Bytes\n";
    return malloc(size);
}

void operator delete(void* var) {
    std::cout << "Deleted\n";
    free(var);
}

int main() {
    std::string name0 = "Ahmed Zaki Marei";
    //std::string name1 = "Lara Mohammed";

    std::cout << name0 << "\n";
    //std::cout << name1 << "\n";
}

When I try to run this code it gives me this output:

Allocated: 8 Bytes
Allocated: 32 Bytes
Ahmed Zaki Marei
Deleted
Deleted

why does it allocate 8 bytes first then allocate 32 bytes? could anyone explain it, please? thx! :)


Solution

  • As C.M. already pointed out in the comments: this is MS STL behavior in Debug mode, smth to do with _ITERATOR_DEBUG_LEVEL. Everything is fine in Release.

    Was curious so I tested it myself and the stack reads this on first breakpoint in new:

    operator new(unsigned int size)
    std::_Default_allocate_traits::_Allocate(const unsigned int _Bytes)
    std::_Allocate<8,std::_Default_allocate_traits,0>(const unsigned int _Bytes)
    std::allocator<std::_Container_proxy>::allocate(const unsigned int _Count)
    std::_Container_proxy_ptr12<std::allocator<std::_Container_proxy>>::_Container_proxy_ptr12<std::allocator<std::_Container_proxy>>(std::allocator<std::_Container_proxy> & _Al_, std::_Container_base12 & _Mycont)
    std::string::basic_string<char,std::char_traits<char>,std::allocator<char>>(const char * const _Ptr)
    main()
    

    Let us look at the basic_string constructor:

        basic_string(_In_z_ const _Elem* const _Ptr) : _Mypair(_Zero_then_variadic_args_t{}) {
            auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal());
            _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2);
    

    and what that _Container_proxy_ptr really is:

    #if _ITERATOR_DEBUG_LEVEL == 0
    #define _GET_PROXY_ALLOCATOR(_Alty, _Al) _Fake_allocator()
    template <class _Alloc>
    using _Container_proxy_ptr = _Fake_proxy_ptr_impl;
    #else // _ITERATOR_DEBUG_LEVEL == 0
    #define _GET_PROXY_ALLOCATOR(_Alty, _Al) static_cast<_Rebind_alloc_t<_Alty, _Container_proxy>>(_Al)
    template <class _Alloc>
    using _Container_proxy_ptr = _Container_proxy_ptr12<_Rebind_alloc_t<_Alloc, _Container_proxy>>;
    #endif // _ITERATOR_DEBUG_LEVEL == 0
    

    It is _Container_proxy_ptr12 (eventually calling .allocate(1)) in Debug and _Fake_proxy_ptr_impl (doing nothing) in Release.