2014-09-17 13 views
7

Ho il seguente codice C++:In che modo std: string mi impedisce di calpestare incautamente i suoi dati?

#include <string> 
#include <iostream> 


int main(int argc, char** argv) 
{ 
    int size; 
    std::string strArray[3]; 
    std::string str0 = "String 0"; 
    std::string str1 = "String 1"; 
    std::string str2 = "String 2"; 

    strArray[0] = str0; 
    strArray[1] = str1; 
    strArray[2] = str2; 

    for (int i = 0; i < 3; i++) 
    { 
     std::cout << strArray[i] << std::endl; 
    } 

    str1.resize(200, 'a'); 

    for (int i = 0; i < 3; i++) 
    { 
     std::cout << strArray[i] << std::endl; 
    } 

    std::cout << str1 << std::endl; 

    std::cin.get(); 
    return 0; 
} 

L'idea è che ho un array che è un blocco contiguo di memoria, in cui ogni elemento è uno std :: string, che sono mutevole e pertanto variabile in dimensione. Mi aspettavo che questo codice si interrompesse da quando ridimensiono lo str1 per occupare più spazio di quello originale e quindi "traboccare" in str2.

Invece ottengo questo output:

stringa0

String1

String2

stringa0

String1

String2

0.123.

String1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ...

ho due domande su questo. Prima di tutto, com'è che aumentando la dimensione di str1 e aggiungendo un sacco di caratteri ad esso non scorre in str2 anche se dovrebbero essere in un blocco contiguo di memoria?

In secondo luogo, come mai quando stampo la matrice per la seconda volta dopo aver ridimensionato str1 E aggiungendo i caratteri ad essa viene ancora stampato lo str1 originale? Ho la sensazione che questo avrà qualcosa a che fare con la risposta alla mia prima domanda, ma non riesco a vedere cosa sta succedendo qui.

+0

Le stringhe nell'array sono stringhe diverse per 'str1',' str2', 'str3'. Anche se non lo fossero, una stringa non traboccherebbe nell'altra. Altrimenti nessuno userebbe mai la classe 'std :: string'. – juanchopanza

+0

I dati internati della classe 'std :: string' sono allocati nell'heap. –

+0

Va notato che la modifica di 'str1' non è la stessa cosa che cambia' strArray [1] '. – MARS

risposta

8

La serie di oggetti string è contigua, ma i dati di stringa effettivi sono memorizzati nell'heap *, quindi i dati di stringa non vengono memorizzati in modo contiguo.

* In realtà, in un'implementazione che utilizza la 'ottimizzazione per piccole stringhe', i dati sono contigui, memorizzati all'interno degli oggetti stringa purché siano sufficientemente piccoli da adattarsi. 'String0' è abbastanza piccolo per tutte le implementazioni SSO che conosco. Una volta che i dati crescono oltre ciò che può essere memorizzato sul posto, l'implementazione lo sposta sull'heap.

La ragione per cui la modifica str1 non influisce sul risultato di stampa strArray[1] è che sono oggetti distinti con alcun rapporto, se non che è stata inizializzata strArray[1] con il valore di str1. Questo è proprio come fare:

int intArray[3]; 
int int0 = 0; 
int int1 = 1; 
int int2 = 2; 

intArray[0] = int0; 
intArray[1] = int1; 
intArray[2] = int2; 

int1 = 10000000; // does not modify intArray[1] 

L'idea è che il comportamento usuale per gli oggetti in C++ è la stessa per i 'tipi primitivi' o 'tipi di valore' si può avere familiarità con in altre lingue. È possibile implementare altri comportamenti in C++, ma std::string è un tipo normale.

+0

Il piccolo buffer di libC++ è troppo piccolo per "String0". –

+1

@SebastianRedl libC++ supporta fino a 22 stringhe 'char' nel suo SSO: http://stackoverflow.com/a/21710033/365496 – bames53

+0

Hai ragione, ho ricordato male l'implementazione. –

1

L'array è contiguo e le stringhe no.

Tu dici str1.resize(200, 'a'); che non ha alcun effetto sulla matrice perché la matrice contiene il value di ciò str1 usato per essere non il reference.

Quindi il valore dell'array non viene sovraccaricato perché il valore all'interno dell'array non è mai stato modificato.

+0

Il valore dell'array non verrebbe sovraccaricato anche se il valore dell'array è stato ridimensionato. 'ridimensiona' alloca nuova memoria se necessario, un' std :: string' non può mai "overflow" –

+0

Stavo solo dicendo che arr [0] non è mai cambiato quindi non può essere overflow. – Jay

2

Come indicato da barnes53, la serie di string memorizza solo l'oggetto string e può semplicemente contenere un puntatore alla matrice di caratteri che rappresenta la stringa.

risolvere la seconda questione è che l'assegnazione matrice avviene per valore anziché per riferimento, il che implica che una copia della stringa è fatta. Ecco perché la modifica della stringa originale non ha alcun effetto sulla versione dell'array.

+0

@Jay, Ci sono molti modi diversi di fraseggiare qualcosa, e possiamo lasciare che l'OP decida ciò che preferisce. Mentre entrambi comprendiamo che stiamo esprimendo la stessa idea, l'OP potrebbe trovare una spiegazione più chiara di un'altra. – merlin2011

Problemi correlati