Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

20.08.2012, 17:52

Nach delete Zeiger auf NULL setzen

Hallo Leute

In Listing 7.8 sagt Heiko Kalista warum man nachdem man Speicher mit delete wieder freigibt den Zeiger auf NULL setzen sollte. Er schreibt, dass man das Programm zum Absturz bringen würde wenn man den Speicher erneut versucht mit delete freizugeben. Aber warum sollte man einen Speicher der schon freigegeben ist nochmal freigeben? Und auf was für einerSSpeicher steht der Zeiger nachdem man ihn frei gegeben hat? Kann mir da einer helfen weil ich verstehe das nicht.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

20.08.2012, 18:00

Vergiss diesen Ratschlag, denn er ist Quatsch.
Es stimmt zwar, dass es einen Fehler gibt, wenn du denselben Speicher doppelt freigeben willst, aber mit "auf NULL setzen" würde man dieses Fehlverhalten nur verstecken. Wenn sowas passiert, ist mit dem Programm etwas nicht OK, und das sollte behoben werden. Gerade darum ist es gut, wenn es abstürzt.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

3

20.08.2012, 18:04

Stell dir vor die Speicherreservierung wäre wie ein Eintrag in das Telefonbuch. Nach dem Kündigen der Telefonnummer (was dem Delete entsprechen würde) sollte man den Eintrag aus dem Telefonbuch entfernen, damit niemand versucht die Nummer an zu rufen.

Du gibst den Speicher also nicht zwei mal frei. Du gibst ihn einmal frei und löschst nachher den Verweis auf ihn.

In dem Beispiel wäre ein Anruf auf die nicht mehr existente Telefonnummer nicht schlimm. In deinem Programm würde es im besten Fall zu einem Absturz führen.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

4

20.08.2012, 18:36

Zitat

Und auf was für einerSSpeicher steht der Zeiger nachdem man ihn frei gegeben hat?


Theorie: Der Pointer an sich zeigt immer noch auf die selbe Adresse im Adressraum deiner Anwendung. Allerdings hat das Betriebssystem deiner Anwendung diesen Speicherbereich weggenommen und damit kannst du diese Adresse nicht mehr benutzen.

Praxis: Da es zeitaufwendig ist immer wegen jeder Änderung zum Betriebssystem zu gehen und dir das Betriebssystem eh immer nur 4kb auf einmal geben oder nehmen kann, wird sich deine new/delete-Implementierung merken, dass dieser Speicherbereich nicht mehr durch ein Objekt belegt ist. Zugriffe darauf funktionieren aber noch, auch wenn der Speicherbereich durch ein weiteres new wieder vergeben ist. Dann passiert irgendwas.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

5

20.08.2012, 21:10

OK, danke schon mal für die ganzen Antworten. Aber eines verstehe ich noch nicht, warum stürzt das Programm ab wenn man eine Adresse, die schon freigegeben wurde nochmal freigibt? Und warum sollte man überhaupt eine Adresse, die schon freigegeben ist nochmal versuchen freizugeben?

eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

6

20.08.2012, 21:15

Vergiss diesen Ratschlag, denn er ist Quatsch.
Es stimmt zwar, dass es einen Fehler gibt, wenn du denselben Speicher doppelt freigeben willst, aber mit "auf NULL setzen" würde man dieses Fehlverhalten nur verstecken. Wenn sowas passiert, ist mit dem Programm etwas nicht OK, und das sollte behoben werden. Gerade darum ist es gut, wenn es abstürzt.
Ganz ehrlich: :dash:
Wieso erwähnt denn niemand die offensichtlich Lösung? Verwende SmartPointers und RAII und die ganze Geschichte mit manuellem Memorymanagment ist geklärt...

Wenn man nun aus irgendwelchen Gründen dies nicht tun kann, dann sollte man gelöschte Pointers auf NULL (bzw nullptr) setzten. Es mag vielleicht für das Debuggen praktisch sein, wenn die Applikation einfach crashed wenn man es nicht macht, aber dieses Verhalten ist nicht definiert (undefined behaviour), es mag zwar in den meisten Fällen der Fall sein, dass die Applikation abstürzt, aber dafür gibt es keine Garantie. Auch muss man dann für das Endprodukt überall nachträglich nochmals die NULL Zuweisung einfügen, schliesslich gilt: "Better safe than sorry."
Der C++ Standard würde anscheinend sogar eine Implementierung von delete erlauben, welche lvalues operanden automatisch auf NULL setzten, jedoch macht dies keiner der grösseren Compilers. (Bjarne Stroustrup's Kommentar zum Thema "Why doesn't delete zero out its operand?")
Bei dieser StackOverflow Frage gibt es auch noch ein paar gute Antworten.

Um hier noch einmal die Lösung zu betonen: Verwende SmartPointers & RAII. ;)

Edit:

Zitat

OK, danke schon mal für die ganzen Antworten. Aber eines verstehe ich noch nicht, warum stürzt das Programm ab wenn man eine Adresse, die schon freigegeben wurde nochmal freigibt? Und warum sollte man überhaupt eine Adresse, die schon freigegeben ist nochmal versuchen freizugeben?
Es kann, muss aber nicht abstürtzen, das Verhalten ist nicht definiert. Der Standard sagt nicht was passieren soll wenn man einen Speicherbereich zwei mal freigeben will und somit ist es nicht definiert und es kann alles Mögliche passieren. ;)
Man sollte dies nicht tun, aber wenn man nicht genug aufpasst und es nicht klar definiert ist, wer der "Besitzer" des Objekts ist, dann könnte man zwei Klassen haben und beide teilen einen Pointer und beide rufen delete auf. Darum ist eine strikte Besitzer Definition wichtig, d.h. wer ist dafür Verantwortlich, dass ein Objekt erstellt und wieder gelöscht wird. Mit RAII und SmartPointers ist dies klar(er) definiert. ;)
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »eXpl0it3r« (20.08.2012, 21:22)


NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

7

20.08.2012, 21:52

Wieso erwähnt denn niemand die offensichtlich Lösung?

Weil ein C++ Programmierer einfach wissen sollte wie manuelle Speicherverwaltung funktioniert. Dein Post hat nichts mit dem Thema zutun.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

8

20.08.2012, 21:52

Wie freundlich du doch wieder bist. :)
Die Frage des TE wurde geklart, weiß nicht warum du meckern musst, als freundlichen Nachtrag wäre es wohl nicht gegangen. ;)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

9

21.08.2012, 01:53

Wenn man nun aus irgendwelchen Gründen dies nicht tun kann, dann sollte man gelöschte Pointers auf NULL (bzw nullptr) setzten. Es mag vielleicht für das Debuggen praktisch sein, wenn die Applikation einfach crashed wenn man es nicht macht, aber dieses Verhalten ist nicht definiert (undefined behaviour), es mag zwar in den meisten Fällen der Fall sein, dass die Applikation abstürzt, aber dafür gibt es keine Garantie. Auch muss man dann für das Endprodukt überall nachträglich nochmals die NULL Zuweisung einfügen, schliesslich gilt: "Better safe than sorry."

Ja, das Verhalten ist undefiniert. Und unter jedem mir bekannten Debugger wird der Fehler sich sofort bemerkbar machen. Ein doppeltes delete kann nur Symptom eines fundamentalen Fehlers im Programm sein. Durch das prinzipielle Nullen des Zeigers nach jedem delete, verliert man die beste Chance, den Fehler in trivialen Fällen sofort zu sehen und zu beheben. Und in komplexeren Fällen wird das Nullen was das angeht potentiell sowieso nichts bewirken, da Pointer in der Regel by value übergeben werden und das Nullsetzen an der einen Stelle daher sehr wahrscheinlich keine Auswirkung auf ein doppeltes delete an etwas anderer Stelle im Programm haben wird. Imo sollte man von so einem Nullen nach delete jedenfalls Abstand nehmen und stattdessen RAII und den Umgang mit einem Debugger lernen... ;)

Um hier noch einmal die Lösung zu betonen: Verwende SmartPointers & RAII. ;)

Absolut!

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »dot« (21.08.2012, 02:12)


David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

10

21.08.2012, 08:12

Ganz ehrlich: :dash:

Du vergisst, dass wir im Forum "C++ für Spieleprogrammierer" sind. :dash:

Es geht um das Buch von Heiko, und das richtet sich an absolute Anfänger, die noch keine Zeile Code programmiert haben und denken, C++ sei ein Vitamin. Da direkt mit Smart Pointern, dem Konzept von Objektbesitz usw. zu kommen, halte ich für keine gute Idee. Erst einmal sollte man lernen, wie man einfach nur new und delete benutzt. Irgendwann wird man schon selber merken, dass man ohne Smart Pointer auf Dauer nicht gut leben kann.

Werbeanzeige