2012-06-21 7 views
7

Wenn wir eine std :: string Implementierung berücksichtigen, die Referenzzählung verwendet, betrachten Sie dieses Szenario:Iteratoren und Referenz gezählt Strings

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; 
} 

Was in L1 und L2 geschieht? Ist die Referenzzählung unterbrochen und wird eine Tiefenkopie durchgeführt? Ich denke schon, aber meine Sorge sagt, dass, wenn dies geschieht, ein einfaches tun:

cout << german[1] << endl; 

oder einfach: durchführen würde unnötig tiefe Kopien

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

in nicht konstanten Kontexten. Habe ich recht? Wie gehen die Implementierungen mit diesem Detail um?

+0

Dies ist ein Grund, warum Referenz gezählt 'std :: string's sind nicht so beliebt. Es funktioniert überhaupt nicht so gut wie ursprünglich gedacht. –

Antwort

6

Sie haben Recht, eine Kopie würde in allen vier Beispielen gemacht (L1, L2 und die beiden unten), obwohl für die letzten beiden es unnötig ist.

Leider, wenn die nichtkonstante Version von operator [] aufgerufen wird oder ein nichtkonstanter Iterator dereferenziert wird, gibt es keine Möglichkeit für die Implementierung zu bestimmen, ob die resultierende nichtkonstante Referenz zum Ändern der verwendet wird Objekt, also muss es auf Nummer sicher gehen und eine Kopie machen.

C++ 11 Funktionen cbegin() und cend() zu Strings und anderen Containern hinzugefügt, die Const-Iteratoren zurückgeben, selbst wenn sie für ein nicht-konstantes Objekt aufgerufen werden. Dies hilft, das Problem zu lindern. Mir ist keine vergleichbare Lösung für den Operator [] bekannt.

Hinweis: Wenn operator [] oder der Operator iterator *() einen Proxy-Typ zurückgeben, wie einige der anderen Beantworter vorgeschlagen haben, ist dies keine Option, weil dadurch die Containeranforderungen verletzt werden Verweise. (Deshalb stimmt jetzt jeder zu, dass vector<bool> ein Fehler ist - er benutzt Proxies auf diese Weise).

(Natürlich, wenn Sie Ihre eigene Referenz-Klasse gezählt zu schreiben, gibt es Sie nichts stoppen Proxy-Typen verwenden, dies zu erreichen.)

2

Eine Möglichkeit, dies zu erreichen, sind Proxy-Klassen. Wenn Sie also in einen String indizieren, erhalten Sie ein Objekt, das aussieht und sich anfühlt wie ein Char. Wenn ein Schreibvorgang ausgeführt wird, verursacht dies eine tiefe Kopie der ursprünglichen Zeichenfolge.