2016-05-06 11 views
22

Considerando un codice come questo:È sicuro aggiungere std :: string a se stesso?

std::string str = "abcdef"; 
const size_t num = 50; 

const size_t baselen = str.length(); 
while (str.length() < num) 
    str.append(str, 0, baselen); 

E 'sicuro di chiamare std::basic_string<T>::append() su se stesso come questo? La memoria sorgente non può essere invalidata ingrandendo prima dell'operazione di copia?

Non ho trovato nulla nello standard specifico per quel metodo. Dice quanto sopra è equivalente a str.append(str.data(), baselen), che a mio avviso potrebbe non essere del tutto sicuro a meno che non vi sia un altro rilevamento di tali casi all'interno di append(const char*, size_t).

Ho controllato alcune implementazioni e mi sono sembrate al sicuro in un modo o nell'altro, ma la mia domanda è se questo comportamento è garantito. Per esempio. "Appending std::vector to itself, undefined behavior?" dice che non è per .

+0

Dovrebbe essere ma come te non riesco a trovare nulla in un modo o nell'altro. 'str + = str;' è legale e si riduce alla stessa cosa quindi suppongo che vada bene. – NathanOliver

+0

@NathanOliver: In realtà, c'è una buona ragione per non renderlo illegale. Con le stringhe, allegare la stessa stringa a se stesso o un sottoinsieme della stringa, è ragionevole. Con 'vector', è molto meno probabile. –

+0

@NicolBolas Lo capisco. Non stavo solo trovando gli standard per supportare la mia tesi. Sembra che lo abbia fatto Rakete1111. – NathanOliver

risposta

15

Secondo §21.4.6.2/§21.4.6.3:

La funzione [basic_string& append(const charT* s, size_type n);] sostituisce la stringa controllata da * questo con una stringa di lunghezza lunghezza() + n cui prima dimensione (Gli elementi sono una copia della stringa originale controllata da * this e i cui elementi rimanenti sono una copia degli elementi n iniziali di s.

Nota: Questo vale per ogni append chiamata, come ogni append può essere implementato in termini di append(const charT*, size_type), come definito dallo standard (§21.4.6.2/§21.4.6.3).

Quindi, fondamentalmente, append fa una copia di str (chiamiamola la copia strtemp), accoda n personaggi di str2 a strtemp, e poi sostituisce str con strtemp.

Per il caso che str2 è str, non cambia nulla, poiché la stringa viene ingrandita quando viene assegnata la copia temporanea, non prima.

Anche se non è esplicitamente indicato nello standard, è garantito (se l'implementazione è esattamente come indicato nello standard) dalla definizione di std::basic_string<T>::append.

Quindi, questo non è un comportamento non definito.

+0

Vedo, grazie - avrei dovuto leggere la definizione di 'append (const charT *, size_type)' più letteralmente. – Yirkha

6

Questo è complicato.

Una cosa che si può dire con certezza. Se si utilizza iteratori:

std::string str = "abcdef"; 
str.append(str.begin(), str.end()); 

allora si sono garantito per essere sicuri. Sì davvero. Perché? Perché la specifica afferma che il comportamento delle funzioni iteratore equivale a chiamare append(basic_string(first, last)). Questo ovviamente crea una copia temporanea della stringa. Quindi se hai bisogno di inserire una stringa in se stessa, sei sicuro di poterlo fare con il modulo iteratore.

Concesso, le implementazioni non devono copiarlo effettivamente. Ma hanno bisogno di rispettare il comportamento standard specificato. Un'implementazione potrebbe scegliere di fare una copia solo se l'intervallo iteratore è all'interno di se stesso, ma l'implementazione dovrebbe comunque essere verificata.

Tutte le altre forme di append sono definite come equivalenti a chiamare append(const charT *s, size_t len). Cioè, la tua chiamata per aggiungere sopra è equivalente a te che stai facendo append(str.data(), str.size()). Quindi, cosa dice lo standard su cosa succede se s è all'interno di *this?

Niente affatto.

L'unico requisito è s:

s punti in una matrice di almeno n elementi di charT.

quanto non espressamente vietare s punta verso *this, allora deve essere consentito. Sarebbe anche estremamente strano se la versione iteratore consentisse l'autoassegnazione, ma la versione di dimensioni del puntatore & non lo fosse.

Problemi correlati