Search code examples
c++stlstdstring

Having hard time understanding std::basic_string memory allocation


I'm currently learning STL and I came across an example made by one of my teachers.

template <class T>
struct SpyAllocator : std::allocator<T>
{
typedef T   value_type;

SpyAllocator(/*vector args*/) = default;

template<class U>
SpyAllocator(const SpyAllocator<U>& other){}

template<class U>
struct rebind
{
    using other = SpyAllocator<U>;
};

T*  allocate(std::size_t n)
{
    T* p = (T*) new char[sizeof(T) * n];

    memorySpy.NotifyAlloc(sizeof(T), n, p);
    return p;
};

void    deallocate(T* p, std::size_t n)
{
    memorySpy.NotifyDealloc(p, n);
    delete (char*)p;
}

typedef T*          pointer;
typedef const T*    const_pointer;
typedef T&          reference;
typedef const T&    const_reference;
};

template <class T, class U>
bool    operator==(const SpyAllocator<T>&, const SpyAllocator<U>&) { return 
false; }

template <class T, class U>
bool    operator!=(const SpyAllocator<T>&, const SpyAllocator<U>&) { return 
false; }

Above is his allocator implementation.

#define String      std::basic_string<char, std::char_traits<char>, SpyAllocator<char>>

He defined std::basic_string as String.

In the main.cpp file,

int main()
{
    DO(String s1 = "Bonjour");
    DO(String s2 = " le monde !");
    DO(String s3 = s1 + s2);
    printf("s3 : %s\n", s3.c_str());

    printf("\nDestroy vector\n\n");
    return 0;
}

He is testing + operator and copy constructor and the result is

String s1 = "Bonjour"

String s2 = " le monde !"

String s3 = s1 + s2
*** Allocate block 1 : 31 elem of 1 bytes

s3 : Bonjour le monde !

Destroy vector

*** Deallocate block 1 : 31 elem of 1 bytes

my questions are:

1- I've counted the number of characters(including \0) of String s1 and String s2, it's 19. But 31 is allocated. Allocate block 1 : 31 elem of 1 bytes

What is the reason behind this?

2- It seems like String s1 and String s2 constructors did not allocate any memory but String s1 and String s2 still have the value.

How is it possible?

Thank you for your time!


Solution

  • Here what we get when we look at the basic_string.h of the STDLib

    enum
    {
        _S_local_capacity = 15 / sizeof(_CharT)
    };
    
    union
    {
        _CharT _M_local_buf[_S_local_capacity + 1];
        size_type _M_allocated_capacity;
    };
    

    We know that std::string is a typedef for a specialization of a std::basic_string with char type.

    basic_string contains a 15 bytes fixed buffer for short strings then we +1 for the \0. So when we concatenate 2 strings which are stored into the small buffer, it will concatenate the whole then add +1 for the \0. So it will be 15 + 15 + 1 = 31.

    That's what I understood from the reading of basic_string.h