Significa “& s [0]” punto a caratteri contigui in uno std :: string?
Domanda
sto facendo alcuni lavori di manutenzione e corse in qualcosa come il seguente:
std::string s;
s.resize( strLength );
// strLength is a size_t with the length of a C string in it.
memcpy( &s[0], str, strLength );
Lo so usando & s [0] sarebbero al sicuro se si trattava di uno std :: vector, ma questo è un uso sicuro di std :: string?
Soluzione
Un'allocazione std :: di stringa non è garantito per essere contigui sotto lo standard C ++ 98/03, ma C ++ 11 forze che sia. In pratica, né io né Herb Sutter sa di un'implementazione che non fa uso di archiviazione contiguo.
Si noti che la cosa &s[0]
è sempre garantita a lavorare dallo standard C ++ 11, anche nel caso stringa di 0-length. Non sarebbe garantito se avete fatto str.begin()
o &*str.begin()
, ma per &s[0]
lo standard definisce operator[]
come:
ritorni :
*(begin() + pos)
sepos < size()
, tuttavia un riferimento a un oggetto di tipoT
con valorecharT()
; il valore di riferimento non deve essere modificato
Proseguendo, data()
è definito come:
Returns:. Un puntatore
p
tale che per ognip + i == &operator[](i)
i
in[0,size()]
(notare le parentesi quadre ad entrambe le estremità della gamma)
Avviso : pre-standardizzazione C ++ 0x non garantiva &s[0]
a lavorare con le stringhe di lunghezza zero (in realtà, era un comportamento esplicitamente definito), e una versione precedente di questa risposta ha spiegato questo; questo è stato risolto in successive bozze standard, quindi la risposta è stato aggiornato di conseguenza.
Altri suggerimenti
Tecnicamente, no, dal momento che std::string
non è tenuto a conservare il suo contenuto in modo contiguo nella memoria.
Tuttavia, in quasi tutte le implementazioni (ogni implementazione di cui sono a conoscenza), i contenuti vengono memorizzati in modo contiguo e questo sarebbe "lavoro".
E 'sicuro da usare. Penso che la maggior parte delle risposte erano corrette una volta, ma lo standard cambiato. Citando dal C ++ 11 di serie, basic_string requisiti generali [string.require] , 21.4.1.5, dice:
Gli oggetti char-come in un oggetto basic_string devono essere memorizzati in modo contiguo. Cioè, per qualsiasi basic_string oggetto s, l'identità e * (s.begin () + n) == & * s.begin () + n deve valere per tutti i valori di n tale che 0 <= N
Un po 'prima che, si dice che tutti gli iteratori sono iteratori ad accesso casuale. Entrambi i bit supportano l'utilizzo della tua domanda. (Inoltre, Stroustrup a quanto pare lo utilizza nel suo libro più recente;))
Non è improbabile che questo cambiamento è stato fatto in C ++ 11. Mi sembra di ricordare che la stessa garanzia è stato aggiunto poi per il vettore, che ha ottenuto anche il dati molto utili () puntatore con quella versione.
La speranza che aiuta.
I lettori dovrebbero notare che questa domanda è stato chiesto nel 2009, quando il C ++ 03 standard è stata la pubblicazione corrente. Questa risposta si basa su tale versione dello standard, in cui std::string
s sono non garantito di utilizzare archiviazione contiguo. Dal momento che questa domanda non è stato chiesto, nel contesto di una particolare piattaforma (come gcc), non faccio ipotesi sulla piattaforma di OP - in particolare, il tempo o non è utilizzato stoccaggio contigious per la string
legale? Forse sì forse no. Sicuro? Probabilmente, ma forse no. Buon codice? Beh, non andiamo lì ...
Perché non basta fare:
std::string s = str;
... oppure:
std::string s(str);
... oppure:
std::string s;
std::copy( &str[0], &str[strLen], std::back_inserter(s));
... oppure:
std::string s;
s.assign( str, strLen );
Il codice potrebbe funzionare, ma più per fortuna che il giudizio, rende ipotesi circa l'implementazione che non sono garantiti. Suggerisco di determinare la validità del codice è irrilevante, mentre si tratta di una inutile complicazione sopra che può essere facilmente ridotto a solo:
std::string s( str ) ;
o se assegnare a un oggetto std :: stringa esistente, semplicemente:
s = str ;
e poi lasciare che std :: stringa stessa determinare come raggiungere il risultato. Se avete intenzione di ricorrere a questo tipo di sciocchezze, allora si può anche non utilizzare std :: string e bastone per quanto si sta reintroducendo tutti i pericoli connessi con stringhe C.
Questo è generalmente non sicuro, indipendentemente dal fatto che la sequenza stringa interna viene memorizzato in continuo o meno. C'è potrebbero essere molti altri dettagli di implementazione relativi a come la sequenza controllata viene memorizzato per oggetto std::string
, oltre alla continuità.
Un vero e proprio problema pratico che potrebbe essere la seguente. Sequenza controllata di std::string
non è necessaria la conservazione come stringa terminata da zero. Tuttavia, in pratica, molti (? La maggior parte) le implementazioni scelgono di sovradimensionare il buffer interno da 1 e memorizzare la sequenza come una stringa terminata da zero in ogni caso perché semplifica l'implementazione del metodo c_str()
: basta restituire un puntatore al buffer interno e si sono fatto.
Il codice che hai citato nella tua domanda non fa alcuno sforzo per zero terminare i dati vengono copiati nel buffer interno. Molto probabilmente semplicemente non sa se lo zero-terminazione è necessario per questa implementazione di std::string
. Molto probabilmente si affida al buffer interno essendo riempiti con zeri dopo la chiamata a resize
, così il carattere aggiuntivo assegnato per lo zero-terminatore dalla implementazione è convenientemente pre-impostato a zero. Tutto questo è un dettaglio di implementazione, il che significa che questa tecnica dipende da alcune ipotesi piuttosto fragili.
In altre parole, in alcune implementazioni, si sarebbe probabilmente necessario utilizzare strcpy
, non memcpy
forzare i dati nella sequenza controllata del genere. Mentre in alcune altre implementazioni dovreste usare memcpy
e non strcpy
.