Wie erfahren Objekte von der zerstörung eines anderen?
-
Ich Programmiere gerade so einen kleinen lamen 2D Space Shooter. Da ist es jetzt so, dass ich eine Basisklasse ObjectBase für alle arten von Objekten haben. Die ObjectBase enthält diverse informationen (Position, Grösse, Ausrichtung etc.) und zwei methoden: step und draw.
Die Methode Step kümmert sich also um die Spiellogik. da die Objekterzeugung sich über ein Singelton hanhaben lässt kann ein Raumschiff z.b. auch wunderbar eine Rakete erzeugen oder sonstige Projektile. Jetzt bleibt nur die frage, was passiert, wenn ein objekt zerstört wird. Das soll es ja wenn möglich auch selber managen (Explosion erzeugen, oder eine Ladung Trümmer die herumfliegen). Nur, wenn sich das Objekt nun selber zerstört... das geht ja irgendwie nicht.
1. Kann ein Objekt seinen eigenen Destruktor aufrufen?
2. Wie erfahren die andere Objekte, dass es zerstört wurde? sonst bleibt ja so eine Objektleiche da irgendwo liegen. und führt womöglich zu undefiniertem verhalten.Was macht man hier? Das Einzige was mir gerade so einfällt, ist es eine Statusvariable zu setzen und das Objekt von ausser zerstören zu lassen.
bin für jede Hilfe danktbar
Gruss japro
-
Hi,
delete this; ist möglich, würde ich dir aber nicht empfehlen, da die anderen Objekte wie du schon gesagt hast, nicht von der Zerstörung erfahren.
Eine Lösung wäre z.B., eine abstrakte Basisklasse SelfDestroyable einzuführen, die einen vector mit Callbackmethoden (nicht Funktionen) enthält, die der Destruktor von SelfDestroyable aufruft. Andere Objekte registrieren sich dann bei SelfDestroyable und kriegen es so mitgeteilt, wenn das Objekt ungültig wird.
Oder du arbeitest wirklich mit einem Statusflag und Reference Counting, ist vielleicht hier sogar besser.
ChrisM
-
ich denke die Frage hängt sehr von dem gesammt Design deines Systems ab. Wie stellst du dir vor, dass man das beantworten soll?
naja, wenn du eine Klasse hast, die alle Objekte verwaltet, dann kann diese ja eine Methode kill_object haben, mit der du Objekte entfernen kannst.
struct manage_singleton { void kill_object(object *foo); void add_object(object *foo); }; typedef singleton<manage_singleton> manage; class object { int live_points; public: object() :live_points(10) { manage::add_object(this); } void shot(unsigned int damage) { if(!live_points-=damage) manage::kill_object(this); } };
-
Hmm, stimmt etwas mehr Informationen könnten nicht schaden. Prizipiell werden ale Objekte eben von einer Klasse namens ObjektManager verwaltet. der ist zwar selber nicht ein Singelton aber ist in einem Singelton enthalten. Das mit der Funktion, die die Objekte entfernt erscheint mir unpraktisch, weil ich dann die ganze Datenstruktur des Objektmanagers durchsuchen muss (vermutlich ein Quadtree, momentan ist es noch eine liste). Ausserdem können noch andere Objekte einen Zeiger auf ein Objekt halten (etwa eine Rakete welche schliesslich ihr Ziel kennen muss). Die müssten das also auch erfahren.
Da das spiel in schritten abläuft und kein Multithreading besitzt werde ich glaube ich einfach ein Statusflag setzen, dann können alle Objekte die einen zeiger auf das Objekt halten darauf reagieren. Am Ende des Schrittes kann der Objekt manager dann selber die objekte zerstören und entfernen.
danke für eure ideen.
mfg japro
-
Ich habe dafür eine safe_pointee-Basisklasse für die Objekte, die im Destruktor alle eingetragenen Pointer, die durch die entsprechende safe_ptr<>-Klasse dargestellt werden, auf 0 setzt. Das ist IMHO wesentlich sauberer als mit Status-Flags rumzuhantieren.
-
Du kannst auch (das hängt aber massiv von der Anzahl der Objekte und deren Verknüpfungen ab) Objekte über eine Publisher-Subscriber-Methodik miteinander verknüpfen, d.h. wenn ein Objekt über die Zerstörung eines anderen informiert werden muß, so wird es in dessen Benachrichtigungskette eingehängt. Wird dieses Objekt zerstört, so ruft es für alle Objekte in seiner Benachrichtigungskette eine Methode auf - danach löscht es sich (kann sich sogar selbst löschen).
Aber das wird zunehmend ungünstiger, je "quadratischer" (also jedes mit jedem) Deine Verknüpfungen zwischen den Objekten sind. Sobald Du in der Nachrichtenkette alle vorhandenen Objekte drin stehen hast weißt Du, daß diese Entscheidung ein Fehldesign war.
-
Möchte nur kurz auf eine böse Gefahr hinweisen, die in diesem Zusammenhang oft auftreten kann.
Nehmen wir an, du klapperst eine Liste ab von (nennen wir sie mal) Actors.
Auf deinem Listenläufer hast du den laufenden Actor, den next hast du dir auch gemerkt, weil der laufende ja zerstört werden soll.
Jetzt reisst dieser Actor beim Sterben (im Destructor) noch einen weiteren Actor mit in den Tod, der sich (ordentlich aufräumend) ordnungsgemäß selbst aus der Actor-Liste entfernt. Mit viel Pech ist dies aber genau der Actor gewesen, auf den dein next-zeiger zeigt...
Die Situation ist also ein potentieller Killer für Iteratoren.