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... 1But 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 worldIn 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
svariable is allocated on the stack... but then, what's calling thenewoperator? 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, andnewis 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.
malloc/freeandnew/delete- are pairoperator newto see who is calling it? Streams do allocate memory, too.std::stringis that it wraps up achar*and own/manages it for you. So when you create astd::string, it allocates some memory to store the actual characters. The constructor can even take a custom allocator.deleteviafree, if that's what you mean, but it was irrelevant to the question, so I omitted it.std::stringclass is performing memory allocation internally. The details aren't particularly important, but is a wrapper around C-style strings (nul-terminated arrays ofchar) that manages memory allocation for you.