Es scheint vielleicht eine dumme Frage zu sein, aber ich muss das wirklich klarstellen:
Bringe das mein Programm in Gefahr?
Wird die const_cast
sogar benötigt?
Wenn ich die Werte der Eingabezeiger an Ort und Stelle ändere, funktioniert es sicher mit std::string
oder erzeugt es undefiniertes Verhalten?
Bis jetzt ist das einzige Problem, dass dies die Zeichenfolge "some_text" beeinflussen könnte, wenn ich den Eingabezeiger ändere und ihn unbrauchbar mache.
%Vor%Danke, dass du mir ein paar Tipps gegeben hast, ich möchte das Shooting in meinem eigenen Fuß vermeiden
Als Beispiel für bösartiges Verhalten: die Interaktion mit der Implementierung von Copy On Write von gcc.
%Vor%In Aktion bei ideone .
Jello, Welt!
Das Problem? Wie der Name schon andeutet, verwendet die GCC-Implementierung von std::string
einen ref-gezählten geteilten Puffer unter dem Cover. Wenn eine Zeichenfolge geändert wird, überprüft die Implementierung genau, ob der Puffer im Moment freigegeben ist, und wenn dies der Fall ist, kopieren Sie sie, bevor Sie sie ändern, und stellen Sie sicher, dass andere Zeichenfolgen, die diesen Puffer gemeinsam haben, nicht von der neuen Schreiboperation betroffen sind. Kopie beim Schreiben).
Nun, mit Ihrem bösen Programm, greifen Sie über eine const-Methode auf den gemeinsam genutzten Puffer zu (der verspricht, nichts zu verändern), aber Sie ändern ihn!
Beachten Sie, dass das Verhalten bei der MSVC-Implementierung, die keine Kopie beim Schreiben verwendet, anders wäre ( "Hello, World!"
würde korrekt gedruckt werden).
Dies ist genau die Essenz von Undefined Behavior .
Um ein inhärent const
-Objekt zu modifizieren, indem die Konstante mit const_cast
weggeworfen wird, ist ein Undefiniertes Verhalten .
string :: c_str () gibt const char *
zurück , dh: ein Zeiger auf eine konstante c-artige Zeichenfolge. Technisch führt dies zu einem nicht definierten Verhalten.
Beachten Sie, dass const_cast
verwendet wird, wenn Sie einen const
-Zeiger auf nicht konstante Daten haben und die nicht konstanten Daten ändern möchten.
Einfaches Casting bringt kein undefiniertes Verhalten hervor. Das Ändern der Daten, auf die gezeigt wird, wird jedoch. ( Siehe auch ISO 14882: 98 5.2.7-7 ).
Wenn Sie einen Zeiger auf modifizierbare Daten haben wollen, können Sie ein
haben %Vor% Das std::string
verwaltet intern seinen eigenen Speicher, weshalb es einen Zeiger direkt auf diesen Speicher zurückgibt, wie es mit der c_str()
-Funktion geschieht. Es stellt sicher, dass es konstant ist, so dass Ihr Compiler Sie warnt, wenn Sie versuchen, es zu ändern.
Wenn Sie const_cast auf diese Weise verwenden, wird diese Sicherheit buchstäblich weggeworfen und ist nur dann eine akzeptable Praxis, wenn Sie absolut sicher sind, dass der Speicher nicht verändert wird.
Wenn Sie das nicht garantieren können, müssen Sie die Zeichenfolge kopieren und die Kopie verwenden. es ist sicherlich viel sicherer, dies in jedem Fall zu tun (Sie können strcpy
verwenden).
Siehe die C ++ Referenz Website:
%Vor%"Erzeugt eine nullterminierte Zeichenfolge (C-String) mit demselben Inhalt wie das String-Objekt und gibt sie als Zeiger auf ein Array von Zeichen zurück.
Ein abschließendes Nullzeichen wird automatisch angehängt.
Das zurückgegebene Array verweist auf einen internen Speicherort mit dem erforderlichen Speicherplatz für diese Zeichenfolge plus dem abschließenden Nullzeichen. Die Werte in diesem Array sollten jedoch nicht im Programm geändert werden und werden nur bis zum letzten Mal unverändert beibehalten nächster Aufruf einer nicht konstanten Elementfunktion des String-Objekts. "
Ja, es bringt Gefahr, weil
input
zeigt auf das, was c_str
gerade passiert, aber wenn some_text
sich jemals ändert oder verschwindet, bleibt ein Zeiger auf Müll. Der Wert von c_str
ist garantiert nur gültig, solange sich die Zeichenfolge nicht ändert. Und formal sogar nur dann, wenn Sie c_str()
auch nicht für andere Strings aufrufen. *input
schreiben, oder? Das ist ein Nein-Nein! Das ist eine sehr schlechte Sache zu tun. Sehen Sie sich an, was std :: string :: c_str () tut und stimmen Sie mir zu.
Zweitens, überlegen Sie, warum Sie einen nichtkonstanten Zugriff auf die Interna von std :: string wünschen. Anscheinend möchten Sie den Inhalt ändern, weil Sie sonst einen const Char-Zeiger verwenden würden. Sie sind auch besorgt, dass Sie die ursprüngliche Zeichenfolge nicht ändern möchten. Warum nicht schreiben
%Vor%Dann haben Sie eine std :: string, mit der Sie umgehen können, ohne das Original zu beeinflussen, und Sie haben std :: string Funktionalität, anstatt mit einem rohen C ++ Zeiger arbeiten zu müssen ...
Ein weiterer Spin ist, dass es extrem schwierig ist, Code zu pflegen. Ein Beispiel: Vor einigen Jahren musste ich einen Code umgestalten, der lange Funktionen enthielt. Der Autor hatte die Funktionssignaturen geschrieben, um const-Parameter zu akzeptieren, aber dann hatte% code sie in der Funktion, um die Konstante zu entfernen. Dadurch wurde die implizite Garantie der Funktion gebrochen und es war sehr schwierig zu wissen, ob sich der Parameter innerhalb des restlichen Codes geändert hat oder nicht.
Kurz gesagt, wenn Sie die Kontrolle über die Zeichenfolge haben und Sie denken, dass Sie sie ändern müssen, machen Sie sie an erster Stelle nicht-konstant. Wenn Sie das nicht tun, müssen Sie eine Kopie erstellen und damit arbeiten.
Tags und Links c++ const-cast