Stavo giocando con il nuovo ed elimina gli operatori che si sovraccaricano quando ho notato qualcosa di strano.Assegnazione stringhe in C++
ho:
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; }
Quando faccio:
int main() { int* x = new int(1); std::cout << *x << std::endl; delete x; return EXIT_SUCCESS; }
Tutto funziona come previsto e ottengo:
Allocating memory... 1
Ma quando lo faccio:
int main() { std::string* s = new std::string("Hello world"); std::cout << *s << std::endl; delete s; return EXIT_SUCCESS; }
ottengo:
Allocating memory... Allocating memory... Hello world
Infatti, quando lo faccio:
int main() { std::string s = "Hello world"; return EXIT_SUCCESS; }
ho ancora
Allocating memory...
!Infine, lo faccio:
int main() { std::string s = "Hello world"; std::cout << &s << std::endl; while (true); }
per ottenere qualcosa di simile:
$ ./test & [1] 8979 Allocating memory... 0xbfc39a68 $ cat /proc/8979/maps | grep stack bfc27000-bfc3c000 ... [stack]
Così ora sono sicuro che la variabile
s
è allocato sullo stack ... ma poi, cosa c'è chiamare l'operatorenew
? La mia ipotesi migliore sarebbe che abbia qualcosa a che fare con l'allocazione di memoria per il letterale attuale,"Hello world"
... ma dovrebbe essere la memoria statica, e lonew
riguarda la memoria dinamica.
Cosa sta succedendo?
Aggiornamento
Dopo aver letto i commenti e il debug l'esempio mi sono voluto concludere che in effetti, una volta che il costruttore di stringa è chiamato, si alloca la memoria sul mucchio per la sua implementazione interna. Questo può essere visto tracciando la chiamata new
:
(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
...
e leggendo lo std :: string (beh, basic_string.tcc) il codice sorgente:
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;
...
}
Quindi sì. La programmazione è fantastica.
nota:. 'Malloc' /' free' e 'new' /' delete' - sono paio –
Perché non si usa un debugger e si interrompe il tuo operatore new per vedere chi lo sta chiamando? Anche gli stream allocano memoria. –
L'intero punto di 'std :: string' è che racchiude un' char * 'e lo possiede/gestisce per te. Quindi quando crei un 'std :: string', assegna un po 'di memoria per memorizzare i personaggi reali. Il costruttore può anche prendere un allocatore personalizzato. – BoBTFish