Warum sollte ich nicht versuchen, den Wert "diesen" Wert zu verwenden, nachdem "dies löschen" verwendet wird?

StackOverflow https://stackoverflow.com/questions/1866461

  •  18-09-2019
  •  | 
  •  

Frage

Im Dieser Absatz von C ++ - FAQ Benutzung von delete this Konstrukt wird diskutiert. 4 Einschränkungen sind aufgeführt.

Beschränkungen 1 bis 3 sehen ziemlich vernünftig aus. Aber warum ist die Einschränkung 4 dort, dass ich sie "nicht untersuchen, sie mit einem anderen Zeiger vergleichen, mit Null vergleichen, drucken, wirken, etwas damit tun können"?

Ich meine this ist ein weiterer Zeiger. Warum kann ich nicht? reinterpret_cast es zu an int oder anrufen printf() seinen Wert ausgeben?

War es hilfreich?

Lösung

Der Grund, warum Sie nach dem Löschen (dieser oder eines anderen Zeigers) nichts mit einem Zeiger machen können, ist, dass die Hardware (und einige ältere Maschinen) fangen könnten, um eine ungültige Speicheradresse in ein Register zu laden. Auch wenn es für alle modernen Hardware in Ordnung ist, besagt der Standard, dass das einzige, was Sie einem ungültigen Zeiger (nicht initialisiert oder gelöscht) tun können, darin besteht, ihm (entweder Null oder von einem anderen gültigen Zeiger) zuzuweisen.

Andere Tipps

Der Wert von 'this' nach dem Aufrufen von Löschen ist undefiniert, und das Verhalten von allem, was Sie damit machen, ist ebenfalls undefiniert. Ich würde zwar erwarten, dass die meisten Compiler etwas Vernünftiges tun, aber es gibt nichts (in der Spezifikation), die den Compiler daran hindert, zu entscheiden, dass sein Verhalten in diesem speziellen Fall Code zum Formatieren Ihrer Festplatte ausstrahlt. Das Aufrufen von undefiniertem Verhalten ist (fast) immer ein Fehler, selbst wenn sich Ihr bestimmter Compiler so verhält, wie Sie es möchten.

Sie könnten dies umgehen, indem Sie eine Kopie des Zeigers (als Ganzzahl) nehmen, bevor Sie Löschen aufrufen.

Aha!

3.7.3.2/4: "... Die Deallocation -Funktion beauftragt den vom Zeiger verwiesenen Speicher und macht alle Zeiger ungültig, die sich auf einen Teil des verhandelten Speichers beziehen. Der Effekt der Verwendung eines ungültigen Zeigerwert Funktion) ist undefiniert ".

Beachten Sie, dass dies "Verwendung des Wertes", nicht "Derferenzieren des Zeigers".

Dieser Absatz ist nicht spezifisch für this, Es gilt für alles, was gelöscht wurde.

Denn jede Aktion, die Sie mit diesem Zeiger ergreifen können, könnte eine Logik auslösen, die auf den Klassenmethoden dieses Objekts interpretiert wird, was zu einem Absturz führen könnte.

Einige der Aktionen, auf die Sie hinweisen, könnten anscheinend "sicher" sein, aber es ist schwierig zu sagen, was innerhalb einer Methode passiert, die Sie anrufen können.

Aus dem Beitrag: "Darf es nicht untersuchen, es mit einem anderen Zeiger vergleichen, mit Null vergleichen, drucken, ihn werfen, etwas damit tun"?

All diese Aktionen können den Betriebsfunktionen ausführen, die mit einem undefinierten Zeiger bewertet werden. Idem für das Casting.

Wenn Sie nun einen renintenpret_cast ausführen, ist das wahrscheinlich eine andere Geschichte, und Sie könnten wahrscheinlich miteinander auskommen, da Neuinterpretation nur etwas zu Stück neu interpretiert ist, ohne einen Methodenaufruf zu beteiligen (soweit ich weiß).

Aus dem gleichen Grund würden Sie keinen anderen Zeiger löschen und dann versuchen, Operationen darauf auszuführen.

b/c Die Adresse, die sich auf jetzt bezieht, und definierte und Sie wissen nicht, was da sein könnte ...

In einem Multi-Thread-Programm, sobald Sie Sie delete Ein Zeiger, der freie Speicherplatz kann von einem anderen Faden zugewiesen werden, der den von verwendeten Raum überschreibt this. Auch in einem Einzel-Thread-Programm, es sei denn, Sie sind sehr vorsichtig mit dem, was Sie vorher anrufen returnAlles, was Sie danach tun delete this könnte Speicher zuweisen und überschreiben, was früher darauf hingewiesen wurde durch this.

In einem im Debug -Modus zusammengestellten Microsoft Visual C ++ ausführbar, zusammengestellt, kompiliert deleteEin Zeiger führt dazu, dass sein Gedächtnis sofort mit einem 0xcc -Testmuster überschrieben wird (nicht mit diesem Muster initialisierte Variablen werden auch initialisiert), um baumelnde Zeigerfehler wie dieses zu identifizieren.

Dies erinnert mich daran, als ich einen Fehler in einem Online-spielbaren Spiel behoben habe, bei dem der Konstruktor eines Feuerwehrobjekts das älteste Feuer löschte, wenn die Gesamtzahl der Brände eine bestimmte Zahl erreicht hatte. Das gelöschte Feuer war manchmal das übergeordnete Feuer, das ein neues Feuer erstellte - Bam, baumelnder Zeigerbug! Es lag nur an Glück, dass dieser Fehler auf völlig vorhersehbare Weise mit dem Speicherallokationsalgorithmus interagierte (das gelöschte Feuer wurde immer mit einem neuen Feuer auf die gleiche Weise überschrieben) - sonst hätte es eine Desynchronisation zwischen Online -Spielern verursacht. Ich fand diesen Fehler, als ich die Art und Weise, wie das Spiel die Speicherzuweisung durchführte, neu geschrieben hat. Aufgrund seiner Vorhersehbarkeit konnte ich, als ich es behoben habe, auch die Emulation seines Verhaltens für die Kompatibilität mit älteren Spielkunden implementieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top