Grob gesagt, ich habe eine Klasse, die ein Array von const unsigned char enthält. Objekte dieser Klasse werden durch eine spezielle Factory-Funktion erstellt, die auch für die Erstellung des Arrays (auf dem Heap) sorgt. Wenn ein Objekt in der Factory-Funktion erstellt wird, erhält es den Zeiger auf das Array. Das Array wird nicht kopiert, das Objekt verwendet nur den angegebenen Zeiger. Bei der Zerstörung wird die Zuteilung des Speicherbereichs aufgehoben, den das Array belegt hat.
%Vor% Nun frage ich mich, ob es irgendwelche Nebenwirkungen gibt, denn new []
gibt unsigned char *
zurück, aber delete []
wird für const unsigned char *
aufgerufen. Ich bekomme jedoch keine Segmentierungsfehler.
Das ist in Ordnung, und nicht-normativer Text im Standard schlägt dasselbe vor:
[C++11: 5.3.5/2]:
Wenn der Operand einen Klassentyp hat, wird der Operand durch Aufrufen der oben erwähnten Konvertierungsfunktion in einen Zeigertyp umgewandelt, und der umgewandelte Operand wird anstelle des ursprünglichen Operanden für den Rest dieses Abschnitts verwendet. In der ersten Alternative ( delete object ) kann der Wert des Operandendelete
ein Nullzeigerwert sein, ein Zeiger auf ein Nicht-Array-Objekt, das von einem vorherigen new-Ausdruck erstellt wurde oder ein Zeiger auf ein Unterobjekt (1.8), das eine Basisklasse eines solchen Objekts darstellt (Abschnitt 10). Wenn nicht, ist das Verhalten nicht definiert. In der zweiten Alternative ( delete array ) kann der Wert des Operandendelete
ein Nullzeigerwert oder ein Zeigerwert sein, der aus einem vorherigen Array new-expression resultiert . Wenn nicht, ist das Verhalten nicht definiert. [Hinweis: bedeutet, dass die Syntax des delete-expression mit dem Typ des vonnew
zugewiesenen Objekts übereinstimmen muss, nicht mit der Syntax des Ausdruck -Endnote] [Hinweis: Ein Zeiger auf einen const-Typ kann der Operand eines delete-expressions sein; Es ist nicht notwendig, die Konstante (5.2.11) des Zeigerausdrucks wegzuwerfen, bevor sie als Operand des Löschausdrucks verwendet wird. -Endnote]
Es gibt eine mögliche Kontroverse aus den folgenden Passagen:
[C++11: 5.3.5/3]:
Wenn in der ersten Alternative ( delete object ) der statische Typ des zu löschenden Objekts sich von seinem dynamischen Typ unterscheidet, sollte der statische Typ eine Basisklasse der dynamischen sein Typ des zu löschenden Objekts und der statische Typ muss einen virtuellen Destruktor haben oder das Verhalten ist nicht definiert. In der zweiten Alternative ( löschen Array ) Wenn der dynamische Typ des zu löschenden Objekts sich von seinem statischen Typ unterscheidet, ist das Verhalten nicht definiert.
Obwohl die Absicht dieser Passage nur für den Umgang mit Polymorphismus erscheint, kann sie in Verbindung mit der folgenden Passage so interpretiert werden, dass streng genommen Ihr Code ist ruft tatsächlich undefiniertes Verhalten auf:
[C++11: 3.9.3/1]:
[..] Die cv-qualifizierten oder cv-unqualifizierten Versionen eines Typs sind unterschiedliche Typen; [..]
Ich bin jedoch ziemlich zuversichtlich, dass dies als Wording-Defect im Standard behandelt werden kann; Die Absicht scheint mir klar zu sein.
Ebenso könnte diese Regel sogar vorschlagen, dass das Programm nicht kompiliert:
[C++11: 12.5.4]:
[..] Wenn ein delete-Ausdruck mit einem unären Operator::
beginnt, wird der Name der Freigabe-Funktion im globalen Gültigkeitsbereich gesucht. Andernfalls, wenn der delete-expression zur Freigabe eines Klassenobjekts verwendet wird, dessen statischer Typ einen virtuellen Destruktor hat, ist die Deallokationsfunktion diejenige, die am Definitionsort des virtuellen Destruktors des dynamischen Typs ausgewählt wurde (12.4). . Andernfalls, wenn der delete-expression verwendet wird, um ein Objekt der KlasseT
oder ein Array davon freizugeben, müssen die statischen und dynamischen Typen des Objekts identisch sein und die Freigabe aufgehoben werden Der Name der Funktion wird im Bereich von T nachgeschlagen. Wenn diese Suche den Namen nicht findet, wird der Name im globalen Bereich nachgeschlagen. Wenn das Ergebnis der Suche nicht eindeutig oder nicht zugreifbar ist oder wenn die Suche eine Funktion zur Aufhebung der Platzierungszuordnung auswählt, wird das Programm schlecht dargestellt.
Aber das ist wiederum nicht die Absicht der Regel, die Polymorphismus in Abwesenheit eines virtuellen Destruktors anspricht und echte Unklarheiten über mehrere Klassen-Deklarationen hinweg.
Zusammenfassend lässt sich sagen, dass Sie bei der Interpretation des Wortlauts dieser Regeln am besten auf die nicht normative, aber sehr klare Anmerkung, mit der wir begonnen haben, eingehen.
Sollte kein Problem sein, da "const" -ness bei "unsigned char" (oder einem anderen Datentyp) es schreibgeschützt macht.
Die Verwendung von "[]" in delete sagt, dass ein Array gelöscht werden muss.
Um zu verstehen, was hinter "delete" und "delete []" steht, lesen Sie dies .
Als erstes sollten Sie vermeiden, diese Art von Arrays in C ++ zu verwenden, stattdessen sollten Sie std::vector<unsigned char>
verwenden.
über das const
-Schlüsselwort. Es teilt dem Compiler und demjenigen, der den Code liest, nur mit, dass dieser Member / diese Variable / dieser Parameter nicht geändert werden soll.
Bei Zeigern ist die Position des const
Schlüsselworts wichtig:
( BEARBEITEN ): Die Antwort von Greyson , wo ich diesen Teil geliehen habe
Das const
-Schlüsselwort markiert den Teil auf der linken Seite als Konstante (wenn es am Anfang ist, ist es für den Typ direkt danach, also sind const unsigned char
und unsigned char const
gleich)
Um den Zeiger als const zu markieren, tun Sie dies (Inhalt ist noch veränderbar):
%Vor%Um den Inhalt als const zu markieren, tun Sie dies:
%Vor%Um beide als Konstante zu markieren:
%Vor% Es ist ein Hinweis für den Compiler und für den Benutzer, damit klar ist, was mit den Daten gemacht wird oder nicht. Wenn der Parameter const unsigned char *
lautet, würde der Benutzer wissen, dass dieser Inhalt nicht geändert wird, wenn er übergeben wird.
weil das Schlüsselwort const
nur dann eine Markierung ist, wenn etwas veränderbar ist, hat es keine Auswirkung auf die Größe selbst. Für delete
sollte es also keinen Effekt haben. (siehe Antworten und Kommentare von Leichtathletikrennen im Orbit und auch " Ist const_cast sicher? " könnte für interres sein).
Aber was ich an Ihrem Code nicht mag, ist, dass der Konstruktor öffentlich ist. Ich könnte es direkt aufrufen, aber da der Parameter const unsigned char* array
ist, würde ich nicht erwarten, dass die Klasse den Inhalt ändert oder dass er bei der Zerstörung gelöscht wird. (Ich würde nicht erwarten, dass sich die direkte Erstellung des Objekts anders als die Verwendung der Factory verhält.)
Also würde ich die Factory-Methode als eine static
-Methode der Klasse machen und den Konstruktor protected
machen.
Tags und Links c++