2012-06-21 11 views
7

Se consideriamo un'implementazione std :: string che utilizza il conteggio di riferimento, si consideri questo scenario:Iteratori e di riferimento contato stringhe

int main() 
{ 
    string english = "Hello"; 
    string german = english; //refcnt = 2 
    string german2 = german; 

    /* L1 */ german[1] = 'a'; 
    /* L2 */ *(german2.begin() + 1) = 'A'; 

    cout << english << endl << german << endl << german2 << endl; 
    return 0; 
} 

Cosa succede in L1 e L2? Il conteggio dei riferimenti è rotto e viene eseguita una copia profonda? Credo di sì, ma la mia preoccupazione dice che se ciò si verifica, facendo un semplice:

cout << german[1] << endl; 

o un semplice:

cout << *(german.begin()) << endl; 

in contesti non-const sarebbe eseguire copie profonde inutili. Ho ragione? In che modo le implementazioni trattano questo dettaglio?

+0

Questo è uno dei motivi per cui riferimento contato 'std :: string's non sono così popolari Non funziona affatto come inizialmente immaginato. –

risposta

6

Sei corretto, una copia verrà eseguita in tutti e quattro gli esempi (L1, L2 e due sotto), anche se per gli ultimi due non è necessario.

Sfortunatamente quando la versione non-const di operatore [] viene chiamata o un iteratore non const è dereferenziato, non vi è alcun modo per l'implementazione di dire se il riferimento non const risultante verrà utilizzato per modificare il oggetto, quindi deve giocare sicuro e fare una copia.

C++ 11 ha aggiunto le funzioni cbegin() e cend() a stringhe e altri contenitori che restituiscono costanti iteratori anche se richiamati su un oggetto non const. Questo aiuta ad alleviare il problema. Non sono a conoscenza di una soluzione comparabile per l'operatore [].

Nota: l'operatore [] o l'operatore iteratore *() restituiscono un tipo di proxy, come suggerito da alcuni degli altri risponditori, non è realmente un'opzione in quanto rompe i requisiti del contenitore, uno dei quali è che queste funzioni restituiscono effettive Riferimenti. (Questo è il motivo per cui tutti ora concordano sul fatto che vector<bool> è un errore - utilizza i proxy in questo modo).

(Naturalmente, se si sta scrivendo la propria classe di riferimento-contati, non c'è nulla ti impedisce di utilizzare i tipi di proxy per raggiungere questo obiettivo.)

2

Un modo per ottenere questo è attraverso le classi proxy. Quindi, quando si indicizza una stringa, se si ottiene un carattere si ottiene un oggetto che appare e si sente come un carattere. Quando una scrittura viene eseguita su di essa, causa una copia profonda sulla stringa originale.