Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String Allocation In C++

Tags:

c++

string

memory

I was playing with the new and delete operators overloading when I noticed something strange.

  1. I have:

    void* operator new(size_t size)
    {
        std::cout << "Allocating memory..." << std::endl;
    
        void* p = malloc(size);
    
        if (NULL == p)
        {
            throw std::bad_alloc();
        }
    
        return p;
    }
    
  2. When I do:

    int main()
    {
        int* x = new int(1);
        std::cout << *x << std::endl;
        delete x;
        return EXIT_SUCCESS;
    }
    

    Everything works as expected and I get:

    Allocating memory...
    1
    
  3. But when I do:

    int main()
    {
        std::string* s = new std::string("Hello world");
        std::cout << *s << std::endl;
        delete s;
        return EXIT_SUCCESS;
    }
    

    I get:

    Allocating memory...
    Allocating memory...
    Hello world
    
  4. In fact, when I do:

    int main()
    {
        std::string s = "Hello world";
        return EXIT_SUCCESS;
    }
    

    I still get Allocating memory...!

  5. Finally, I do:

    int main()
    {
        std::string s = "Hello world";
        std::cout << &s << std::endl;
        while (true);
    }
    

    To get something like:

    $ ./test &
    [1] 8979
    Allocating memory...
    0xbfc39a68
    $ cat /proc/8979/maps | grep stack
    bfc27000-bfc3c000 ... [stack]
    

    So now I'm sure the s variable is allocated on the stack... but then, what's calling the new operator? My best guess would be it has something to do with the memory allocation for the actual literal, "Hello world"... but it's supposed to be static memory, and new is all about dynamic memory.

What's going on?

Update

After reading the comments and debugging the example myself I wanted to conclude that indeed, once the string constructor is called, it allocates memory on the heap for its internal implementation. This can be seen by tracing the new call:

(gdb) b 13 // that's the std::cout << "Allocating memory..." << std::endl; line
(gdb) r
... Breakpoing 1, operator new (size=16) at test.cpp:13 ...
(gdb) backtrace
#0 operator new (size=16) at main.cpp:13
#1 std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) () from /usr/lib/libstdc++.so.6
...

And reading the std::string (well, basic_string.tcc) source code:

template<typename _CharT, typename _Traits, typename _Alloc>
typename basic_string<_CharT, _Traits, _Alloc>::_Rep*
basic_string<_CharT, _Traits, _Alloc>::_Rep::
_S_create(size_type __capacity, size_type __old_capacity,
          const _Alloc& __alloc)
{

   ...

    void* __place = _Raw_bytes_alloc(__alloc).allocate(__size);
   _Rep *__p = new (__place) _Rep; // Bingo!
   __p->_M_capacity = __capacity;

   ...

}

So yeah. Programming's cool.

like image 537
Dan Gittik Avatar asked Jul 23 '13 12:07

Dan Gittik


1 Answers

When you write

std::string s = "Hello world";

you are calling the constructor string (const char* s);, the specification of this constructor is Copies the null-terminated character sequence (C-string) pointed by s. So the constructor allocates memory to store the copy.

like image 150
hivert Avatar answered Sep 19 '22 15:09

hivert