Der Code meines Kollegen sah so aus:
%Vor% Seine Anwendung stürzt ab und ich denke, dass dies darauf zurückzuführen ist, dass s
außerhalb des Bereichs liegt, da die Bedingung nur bis zu s.size() - 1
gehen sollte.
Aber andere Leute neben mir sagen, es gab in der Vergangenheit eine Diskussion darüber, dass das legal ist. Kann mir bitte jemand das aufräumen?
Lassen Sie uns die Möglichkeit auslassen, dass *d
ungültig ist, da dies nichts mit dem zu tun hat, worauf die Frage gerichtet zu sein scheint: ob std::string operator[]()
wohldefiniertes Verhalten beim Zugriff auf das "Element" am Index std::string::size()
hat oder nicht.
Der C ++ 03 Standard hat die folgende Beschreibung von string::operator[]()
(21.3.4 " basic_string
element access"):
%Vor%Rückgabe: Wenn
pos < size()
, gibtdata()[pos]
zurück. Andernfalls, wennpos == size()
, gibt die const-VersioncharT()
zurück. Andernfalls ist das Verhalten nicht definiert.
Da s
im Beispielcode const
ist, ist das Verhalten gut definiert und s[s.size()]
gibt ein Nullzeichen zurück. Wenn s
jedoch kein const string
ist, ist das Verhalten nicht definiert.
C ++ 11 behebt dieses Odd-Ball-Verhalten der const
-Version so anders als die nicht-const-Version in diesem Kantenfall. C ++ 11 21.4.5 " basic_string
element access" sagt:
%Vor%Benötigt:
pos <= size()
.Rückgabe:
*(begin() + pos
) wennpos < size()
, sonst eine Referenz auf ein Objekt vom Typ T mit dem WertcharT()
; der referenzierte Wert soll nicht geändert werden.
So ist für einen C ++ 11-Compiler das Verhalten wohldefiniert, unabhängig davon, ob string
const
ist oder nicht.
Ohne Bezug auf die Frage finde ich es etwas seltsam, dass C ++ 11 sagt, dass "der referenzierte Wert nicht geändert werden soll" - es ist mir nicht klar, ob diese Klausel nur in dem Fall gilt, in dem pos == size()
. Ich bin mir ziemlich sicher, dass es eine Menge existierenden Codes gibt, der Dinge wie s[i] = some_character;
tut, wobei s
eine nicht-konstante std:string
und i < s.size()
ist. Ist das undefiniertes Verhalten jetzt? Ich vermute, dass diese Klausel nur für das Sonderfallobjekt charT()
gilt.
Eine weitere interessante Sache ist, dass keiner der Standards zu verlangen scheint, dass die Adresse des Objekts, das für s[s.size()]
zurückgegeben wurde, in irgendeiner Weise mit der Adresse des Objekts in Zusammenhang steht, das für s[s.size() - 1]
zurückgegeben wurde. Mit anderen Worten, es scheint so, als ob der zurückgegebene charT()
-Referenz nicht zusammenhängend mit dem Ende der String-Daten sein muss. Ich vermute, dass dies den Implementierern die Möglichkeit gibt, auf Wunsch nur eine Referenz auf eine einzelne statische Kopie dieses Sentinel-Elements zurückzugeben (dies würde auch die Einschränkung "darf nicht geändert werden" von C ++ 11 erklären, vorausgesetzt, sie gilt nur für das Besondere) Fall).
%Vor%Wenn
pos==size()
,
- Die const-Version gibt einen Verweis auf das Zeichen mit dem Wert CharT () (das Nullzeichen) zurück. (bis C ++ 11)
- Beide Versionen geben einen Verweis auf das Zeichen mit dem Wert CharT () (das Nullzeichen) zurück. Das Ändern des Nullzeichens durch nicht konstante Referenz führt zu undefiniertem Verhalten. (seit C ++ 11)
Es ist also OK, solange Sie das Nullzeichen nicht ändern.
Wenn du es so machen willst (der Code deines Kollegen versucht, auch das abschließende
zu kopieren), kannst du c_str()
i < s.size()
. d
und hängen Sie anschließend %code%
manuell an. Bearbeiten:
Nun, nach den anderen Antworten zu urteilen, bin ich eher geneigt, jetzt zu denken, dass der Kommentar von Abyx korrekt ist: Das Array %code% könnte überlaufen (oder es könnte nicht einmal zugewiesen werden). Überprüfe das zuerst.
Aber stellen Sie sicher, dass Sie auch %code% kopieren!