I was playing with the new and delete operators overloading when I noticed something strange.
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;
}
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
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
In fact, when I do:
int main()
{
std::string s = "Hello world";
return EXIT_SUCCESS;
}
I still get Allocating memory...
!
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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With