In C ++ 11 basic_string::c_str
ist genau das gleiche definiert wie basic_string::data
, was wiederum genau das gleiche ist wie *(begin() + n)
und *(&*begin() + n)
(wann 0 <= n < size()
).
Ich kann nichts finden, bei dem die Zeichenfolge immer ein Nullzeichen am Ende haben muss.
Bedeutet dies, dass c_str()
nicht mehr garantiert wird, dass eine nullterminierte Zeichenfolge erzeugt wird?
c_str
keine NULL-terminierte Zeichenfolge zurückgegeben würde, wäre dies die am häufigsten falsch benannte Funktion aller Zeiten.=
In verpasst0 <= n <= size()
... alles ist in Ordnung, wenn Sie es einschließen, wie es der Standard tutAntworten:
Zeichenfolgen sind jetzt erforderlich, um intern nullterminierte Puffer zu verwenden. Schauen Sie sich die Definition von
operator[]
(21.4.5) an:Rückblickend auf
c_str
(21.4.7.1/1) sehen wir, dass es definiert ist in Bezug aufoperator[]
:Und beide
c_str
unddata
müssen O (1) sein, sodass die Implementierung effektiv gezwungen ist, nullterminierte Puffer zu verwenden.Wie David Rodríguez - dribeas in den Kommentaren ausführt , bedeutet die Rückgabewertanforderung außerdem, dass Sie
&operator[](0)
als Synonym für verwenden könnenc_str()
, sodass das abschließende Nullzeichen im selben Puffer liegen muss (da*(p + size())
muss gleich seincharT()
). Dies bedeutet auch, dass selbst wenn der Terminator träge initialisiert wird, es nicht möglich ist, den Puffer im Zwischenzustand zu beobachten.quelle
c_str
unddata
müssen eine O (1) -Operation sein, was bedeutet, dass sie keine Kopie im laufenden Betrieb erstellen können. Darüber hinaus bedeutet das Erfordernisoperator[]
, dass die Ausgabe übereinstimmt , dass sie entweder bereits nicht beendet ist oder dass der Aufruf vondata
/c_str
muss den Abschluss nicht hinzufügen, bevor der Zeiger zurückgegeben wird. Darüber hinaus muss die Zeichenfolge vor dem Aufruf Platz für diesen Terminator haben , um die O (1) -Anforderung aufrechtzuerhalten. Technisch gesehen ist der String muss nicht nul beendet, sonderndata()
tut&operator[](size()) == &operator[](size()-1) + 1
Bedeutet, dass - dh wennoperator[](size())
ein Verweis auf eine\0
außerhalb der Zeichenfolge zurückgegeben wird, diese Anforderung niemals erfüllt werden kann.c_str()
auf einen Puffer der Länge zeigen musssize()+1
. 21.4.5 besagt, dass das letzte Element dieses Puffers den WertcharT()
- mit anderen Worten das Nullzeichen - haben muss.charT()
das Nullzeichen ist. Dies ist eindeutig der Fall, wenn dies der FallcharT
istchar
. Der Standard ist ein bisschen vage (mehr als ein bisschen vage) in Bezug auf die Bedeutung vonwchar_t
.Tatsächlich stimmt der neue Standard, dass .data () und .c_str () jetzt Synonyme sind. Es heißt jedoch nicht, dass .c_str () nicht mehr nullterminiert ist :)
Es bedeutet nur, dass Sie sich jetzt darauf verlassen können, dass .data () auch mit Null abgeschlossen wird.
Beachten Sie, dass dies NICHT bedeutet, dass ein gültiger std :: string als C-String behandelt werden kann, da std :: string eingebettete Nullen enthalten kann, die den C-String vorzeitig beenden, wenn sie direkt als const char * verwendet werden.
Nachtrag:
Ich habe keinen Zugriff auf die tatsächlich veröffentlichte endgültige Spezifikation von C ++ 11, aber es scheint, dass der Wortlaut tatsächlich irgendwo im Revisionsverlauf der Spezifikation gestrichen wurde: z. B. http://www.open-std.org/jtc1/ sc22 / wg21 / docs / papers / 2011 / n3242.pdf
quelle
Operator[](i)
Ihres Beitrags angezeigt werden, da sie derzeit als Link interpretiert werden, wodurch der Text nicht mehr verständlich ist.Die "Geschichte" war, dass vor langer Zeit, als alle in einzelnen Threads arbeiteten oder zumindest die Threads Arbeiter mit ihren eigenen Daten waren, sie eine String-Klasse für C ++ entwarfen, die die Handhabung von Strings einfacher machte als zuvor, und sie überlasteten Operator + zum Verketten von Zeichenfolgen.
Das Problem war, dass Benutzer so etwas tun würden:
und jede Verkettung würde eine temporäre erzeugen, die eine Zeichenfolge implementieren musste.
Daher hatte jemand die Gehirnwelle der "faulen Auswertung", so dass Sie intern eine Art "Seil" mit allen Zeichenfolgen speichern konnten, bis jemand es als C-Zeichenfolge lesen wollte. An diesem Punkt würden Sie die interne Darstellung in einen zusammenhängenden Puffer ändern .
Dies löste das obige Problem, verursachte jedoch eine Menge anderer Kopfschmerzen, insbesondere in der Multithread-Welt, in der erwartet wurde, dass eine .c_str () -Operation schreibgeschützt ist / nichts ändert und daher nichts gesperrt werden muss. Vorzeitiges internes Sperren in der Klassenimplementierung für den Fall, dass jemand Multithreading durchführte (wenn es nicht einmal einen Threading-Standard gab), war ebenfalls keine gute Idee. Tatsächlich war es teurer, dies zu tun, als jedes Mal einfach den Puffer zu kopieren. Der gleiche Grund, warum die Implementierung "Beim Schreiben kopieren" für Zeichenfolgenimplementierungen abgebrochen wurde.
Daher
.c_str()
stellte sich heraus, dass es am sinnvollsten ist , eine wirklich unveränderliche Operation durchzuführen. Könnte man sich jedoch in einem Standard, der jetzt Thread-fähig ist, darauf "verlassen"? Aus diesem Grund hat der neue Standard entschieden, dass dies eindeutig möglich ist, und daher muss die interne Darstellung den Nullterminator enthalten.quelle
string
hatte auch die seltsame Eigenschaft, dass die erste Nicht-Konstantebegin()
Iteratoren ungültig machen würde!Gut erkannt. Dies ist sicherlich ein Fehler in der kürzlich verabschiedeten Norm; Ich bin sicher, dass es nicht die Absicht gab, den gesamten aktuell verwendeten Code zu brechen
c_str
. Ich würde einen Fehlerbericht vorschlagen oder zumindest die Frage stellencomp.std.c++
(die normalerweise vor dem Ausschuss landet, wenn es sich um einen Fehler handelt).quelle
21.4.2/2
sagt, dass.data()
für eine leere Zeichenfolge nicht wirklich nullterminiert ist (.data()+1
ist nicht gültig, sollte aber ein Zeiger jenseits der sein\0
)