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?

È stato utile?

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) se pos < size(), tuttavia un riferimento a un oggetto di tipo T con valore charT(); il valore di riferimento non deve essere modificato

Proseguendo, data() è definito come:

  

Returns:. Un puntatore p tale che per ogni p + 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::strings 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top