Wie verhindert man am besten dass Speicher ausversehen verändert wird? (C++11)
-
Der Titel ist ein bisschen nichtssagend, aber mir ist nichts besseres eingefallen. Folgender Code verdeutlicht denke ich mein Problem:
#include <string.h> #include <iostream> class X final { public: explicit X(const char *const str); ~X(); const char *const str; }; X::X(const char *const str): str("") { auto s = new char[strlen(str)+1]; strcpy(s, str); *((char **) (&this->str)) = s; } X::~X() { delete[] str; } int main() { X x("hello"); std::cout << x.str << std::endl; return 0; }Davon mal abgesehen dass ich hier einen C header benutze, hat der Code (für mich) zwei Probleme:
- str soll nicht aus versehen verändern werden, daher ist es als const markiert. Damit kann ich allerdings str nur noch über die Initialisierungsliste des ctors verändern.
- Dies führt zum nächsten Problem: Die Klasse muss ihre Ressource wieder frei geben. Da ich nicht weiß ob der Speicher auf den der übergebene pointer zeigt irgendwann mal deleted wird will ich den Inhalt kopieren.Beide Ziele kann ich erreichen indem ich str mit einem leeren string initialisiere und dann im ctor den pointer gleich wieder überschreibe, das ist aber voll hässlich.
Eine andere Lösung wäre, den Speicher zu kopieren bevor die Instanz erzeugt wird. Dann muss ich da aber jedes mal dran denken wenn ich die Klasse instanziieren will, deswegen mag ich diese Lösung nicht.
Jetzt meine Frage: Lohnt es sich überhaupt str als const zu deklarieren? Ich kann das Schlüsselwort trivialerweise mit einem cast umgehen, wie oben gezeigt (allerdings ist das Ziel nur, dass man nicht aus versehen den Pointer verändert bzw. das worauf er zeigt). Gibt es eine bessere Vorgehensweise um zu verhindern, dass Speicher aus versehen mehrmals deleted/überschrieben wird?
-
Wenn Du mit 'aus Versehen' meinst, dass Du ihn von außerhalb der Klasse veränderst, dann mach ihn
private.
Ansonsten:
Warum nimmst Du nicht einenstd::string? Den kannst Du
constmachen, in der Initialisierungsliste versorgen und brauchst Dich nicht um Speicherfreigabe zu kümmern ...

-
Dein Code erzeugt undefiniertes verhalten, ist also schon mal nicht von der Partie.
Am bequemsten geht es hier mit
string. Der kümmert sich nämlich selbst um Speicherfreigabe und die Kopie und verkürzt den Code erheblich:class X final { public: explicit X(const char* str) : str(str) {} std::string const str; };
-
Der char* war nur ein Beispiel, das kann auch ein pointer auf irgendetwas anderes sein. std::string zu benutzen bringt also nur in diesem Beispiel etwas.
private möchte ich die Variable nicht machen, da ich sie von außen wieder lesen können möchte.
Und warum erzeugt der Code undefiniertes Verhalten?
-
Antoras schrieb:
private möchte ich die Variable nicht machen, da ich sie von außen wieder lesen können möchte.
Wenn du nicht willst, dass von außen dran rumgespielt werden kann schreib dir nen getter.
-
Antoras schrieb:
private möchte ich die Variable nicht machen, da ich sie von außen wieder lesen können möchte.
public: const XYZ& GetXYZ() const {return myXYZ;} private: XYZ myXYZ;
-
Antoras schrieb:
Und warum erzeugt der Code undefiniertes Verhalten?
Weil du versuchst ein
constObjekt zu modifizieren.Der char* war nur ein Beispiel, das kann auch ein pointer auf irgendetwas anderes sein. std::string zu benutzen bringt also nur in diesem Beispiel etwas.
Dann nimm eben
std::vector. Auf jeden Fall etwas dass dir manuelle Speicherverwaltung abnimmt.
-
Arcoth schrieb:
Antoras schrieb:
Und warum erzeugt der Code undefiniertes Verhalten?
Weil du versuchst ein
constObjekt zu modifizieren.Warum ist das undefiniert? Weil der Compiler Optimierungen durchführen könnte?
Die Lösung mit dem Getter hat den Nachteil, dass man dann immer
x()anstelle vonxschreiben muss.std::vectorist auch eine zusätzliche Indirektion, aber damit muss man wohl leben.
-
Antoras schrieb:
Arcoth schrieb:
Antoras schrieb:
Und warum erzeugt der Code undefiniertes Verhalten?
Weil du versuchst ein
constObjekt zu modifizieren.Warum ist das undefiniert? Weil der Compiler Optimierungen durchführen könnte?
Ja, unter anderem.
Die Lösung mit dem Getter hat den Nachteil, dass man dann immer
x()anstelle vonxschreiben muss.std::vectorist auch eine zusätzliche Indirektion, aber damit muss man wohl leben.Gewöhn dich dran. Das ist die beste Lösung.
-
Nathan schrieb:
Gewöhn dich dran. Das ist die beste Lösung.
Ok, dann mache ich das so. Danke für alle Antworten!