2013-07-23 2 views
6

Stavo giocando con il nuovo ed elimina gli operatori che si sovraccaricano quando ho notato qualcosa di strano.Assegnazione stringhe in C++

  1. 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; 
    } 
    
  2. 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 
    
  3. 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 
    
  4. Infatti, quando lo faccio:

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

    ho ancora Allocating memory...!

  5. 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'operatore new? 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 lo new 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.

+0

nota:. 'Malloc' /' free' e 'new' /' delete' - sono paio –

+1

Perché non si usa un debugger e si interrompe il tuo operatore new per vedere chi lo sta chiamando? Anche gli stream allocano memoria. –

+2

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

risposta

5

Quando si scrive

std::string s = "Hello world"; 

si sta chiamando il costruttore string (const char* s);, la specifica di questo costruttore è Copies the null-terminated character sequence (C-string) pointed by s. Quindi il costruttore alloca la memoria per memorizzare la copia.

+0

Il * te * nell'ultima frase è confuso, sarebbe meglio essere frasato * Quindi 's' necessario allocare la memoria per memorizzare la copia *, ma allora ti consiglio di cambiare il nome del parametro del costruttore poiché è anche' s' . –

+0

È meglio ora? – hivert

+0

Sembra migliore (almeno per me), grazie :) –

1
std::string s = "Hello world"; 

lato destro mano è memoria statica s costruttore alloca nuova memoria e copia "Ciao mondo",

0

std :: string è una struttura che incapsula una stringa in stile C.

Una prima allocazione viene effettuata per la struttura del contenitore stringa.
Una seconda allocazione è per una copia della stringa che viene eseguita nella costruzione della stringa.

0

L'oggetto string alloca lo spazio per i caratteri effettivi utilizzando new. Questo è fatto nel costruttore della stringa.

3

Esempio 3 .: (prima nota, è necessario utilizzare std::string *s anziché std::string s, poiché new restituisce un puntatore).

Utilizzando gdb Ho impostato un punto di interruzione sulla linea di std :: cout e backtraced le due chiamate:

Il primo è il new hai scritto nel codice. La seconda capita di essere chiamato dall'interno libstdC++ so.6 (nel mio caso):

(gdb) backtrace 
#0 operator new (size=36) at test.cpp:6 
#1 0x00007ffff7b78a89 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&)() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#2 0x00007ffff7b7a495 in char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag)() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#3 0x00007ffff7b7a5e3 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#4 0x0000000000400da1 in main() at test.cpp:20 
+0

+1 per non solo rispondere, ma anche dare un suggerimento su come indagare. –