delete this ?
-
Hallo zusammen!
Ich habe einen Gewissenskonflikt ;).
Und zwar habe ich vor, eine kleine Simulation zu schreiben. In dieser werden sich "Lebewesen" befinden, die ich gerne über eine Klasse repräsentieren möchte. Nunja, wenn diese "Lebewesen" eben nicht ausreichend Nahrung finden, sollten sie sterben. Die Grenze wann dies erreicht ist, weiß jedes Lebewesen selbst über sich. Daher habe ich vor, dass sich dieses Lebewesen selbst zerstört, was bedeuten würde, dass es selbst delete this aufruft.
Natürlich habe ich auch meine Bedenken bei diesem Vorgehen. Gegoogelt habe ich bereits, und auch vieles brauchbares gefunden. Der Grundtenor hier war, dass es gefährlich ist, delete this aufzurufen, es aber dennoch immer wieder Ausnahmen gibt, wo es sinnvoll ist, diesen Weg trotzdem zu gehen.
Ich weiß, dass von meinem Programm aus, ich Objekte dieses Typs nur über den Operator new angelegt werden, was eine gewisse Sicherheit garantiert.Haltet ihr es für vertretbar, delete this zu benutzen?
Danke im Voraus,
Flux
-
Hm, woher weiß dann die Gemeinde das ein "Lebewesen" gestorben ist ?
(Du verwaltest die Lebewesen doch sicherlich irgendwo wo sie raus müssen wenn sie gestorben sind ?)
-
Knuddlbaer schrieb:
Hm, woher weiß dann die Gemeinde das ein "Lebewesen" gestorben ist ?
(Du verwaltest die Lebewesen doch sicherlich irgendwo wo sie raus müssen wenn sie gestorben sind ?)Ja, ich habe vor, das Spielfeld als ein 2dimensionales Array zu repräsentieren (Typ: Zeiger auf "Lebewesen"). Bevor sich das Lebewesen selbst umbringt, sollte dieser Zeiger natürlich noch auf 0 gesetzt werden (was bei mir dann bedeuteten würde, dass sich "nichts" auf diesem Feld befindet).
-
Wobei ich aber gerade fast mehr dazu tendiere, ein Vector mit "Lebewesen" anzulegen, und sich die Lebewesen ihre Koordinaten selber merken zu lassen, was ich auch sowieso machen müsste, in der vorherigen Version. Ist meiner Meinung nach geradliniger. Dennoch aber müsste ich delete this aufrufen.
-
Frage:
Steh ich da nich irgendwie undefiniert wenn ich im Objekt delete this aufrufe ?
Wenn ich in nen Raum gehe und mich da umbringe komm ich alleine nicht mehr aus dem Raum raus. Ist das definiert wie es im Object weitergeht wenn delete this durchlaufen wurde ?Variante A:
void foo::SelbstMord
{
delete this;
foo(); // Dürfte nich mehr gehen ?
}void foo::SelbstMord
{
delete this;
} // Klappt das noch definiert das ich hier rauskomme ? Am ende wars ja doch nur ein Funktionsaufruf ?!Ne Antwort auf die eigentliche Frage kann ich Dir nich liefern
Aber was zum grübeln:Wenn ich 1000 Lebewesen im Vector halte, 100 sterben und 100 neu auf die Welt kommen, hat mein vector, wenn ich nur den Zeiger auf 0 setze irgendwann 1100 Werte. Da müsstest doch Ohnehin irgendwann mal aufräumen ?
Warum nicht dort das Objekt fragen ob es noch lebt ? (Wie der Rettungsfuzi der dem Opfer zur hilfe kommen will ;o)Ansonsten wäre ne liste besser wenn die Leuts ihre Koordinaten speichern.
Ansonsten müsstest Du eigentlich in vector<vector< > > nich nen Container packen da sonst auf jeder Koordinate nur einer Leben kann.
sry für das verbeiargumentieren an der eigentlichen Frage
-
Also du willst das feld mit einer Matrix representiren. Und du willst das dass Element(das ein Lebewessen representiert) auf NULL steht wenn das Lebewesen tod ist, wenn ich dass richtig verstanden habe und du vor hast das Feld dynamisch zu halten, wäre es gut wenn du das mit hilfe einer Datenstruktur, die man "sperse matrix" nent zu lösen.
Wenn du Probleme mit der Inplementation hast kann ich dir helfen, dass zu schreiben dauert nicht lendger als ca. 20 min (Ich weis nicht, was für Anfragen du an die Anwendung hast)
-
Ich hab mir für den Fall einen allgemeinen Smart Pointer geschrieben, der automatisch auf 0 gesetzt wird, wenn das angepointerte Objekt freigegeben wird (das dafür allerdings von einer bestimmten Klasse abgeleitet sein muss). Das ist zwar etwas allgemeiner und deswegen vermutlich nicht ganz so effizient wie deine Lösung, aber wenn ich ihn trotzdem mal posten soll, sag Bescheid. Er hat zwar nicht jedes erdenkliches Feature, _sollte_ aber immerhin sicher und einfach zu benutzen sein. Ich benutze für ein ungefähr ähnliches Problem eine Kombination aus diesem Pointer und boost::shared_ptr und bin soweit ziemlich zufrieden damit.
-
Also dass mit denn Vektoren ist ja im Ansatz gut, nur wirt es bei der umsetzung zur Problemen kommen, da hat meine Version vorteile
-
Knuddlbaer schrieb:
Frage:
Steh ich da nich irgendwie undefiniert wenn ich im Objekt delete this aufrufe ?
Wenn ich in nen Raum gehe und mich da umbringe komm ich alleine nicht mehr aus dem Raum raus. Ist das definiert wie es im Object weitergeht wenn delete this durchlaufen wurde ?Hab ich mir auch schon überlegt. Drum gegoogelt, und hab dort ja gefunden, dass ein delete this manchmal (anscheinend sogar in der MFC) durchgeführt wird. Also denke ich mir, wird es gehen... Eine Funktion danach aufrufen, würde ich aber natürlich nicht mehr machen, wobei ich auch nicht weiß, wie sich das Objekt dann verhalten würde.
Ne Antwort auf die eigentliche Frage kann ich Dir nich liefern
Aber was zum grübeln:Wenn ich 1000 Lebewesen im Vector halte, 100 sterben und 100 neu auf die Welt kommen, hat mein vector, wenn ich nur den Zeiger auf 0 setze irgendwann 1100 Werte. Da müsstest doch Ohnehin irgendwann mal aufräumen ?
Warum nicht dort das Objekt fragen ob es noch lebt ? (Wie der Rettungsfuzi der dem Opfer zur hilfe kommen will ;o)Ja, ich muss aufräumen. Und das werde ich auch machen, alternativ zum delete this habe ich mir auch überlegt, eine Eigenschaft "dead" für jedes Lebwesen anzulegen, und dann eben an geeigneter stelle (vor Neuzeichnung des "Spielfeldes") alle Lebwesen, für die gilt dead==true zu löschen.
EDIT: Ich will aber auf keinen Fall, von der stelle wo ich aufräume, erst noch ermitteln, ob das Lebewesen noch lebt. Das ist mir nicht allgemein genug, da ja verschiedene Lebewesen aus anderen Gründen etc. sterben können. Daher die Idee mit der Variable "dead".Ansonsten wäre ne liste besser wenn die Leuts ihre Koordinaten speichern.
Stimmt, hört sich interessant an. Ist ne Liste schneller?
Ansonsten müsstest Du eigentlich in vector<vector< > > nich nen Container packen da sonst auf jeder Koordinate nur einer Leben kann.
sry für das verbeiargumentieren an der eigentlichen Frage
Ja, eben, das ist eines der Probleme die bei der Matrix-variante einherkommen. Und da bevorzuge ich es, wenn die "Lebewesen" selbst wissen, wo sie sich gerade befinden.
Und du hast alles andere als an der Frage vorbei argumentiert ;)! (keine Ironie) Im gegenteil, danke soweit.
@tower:
ich habe noch nie etwas von einer sperse matrix gehört. Erklärst du mir kurz, was genau man darunter versteht? Ansonsten, bin ich wie gesagt, schon von der Matrix Idee abgekommen.
-
operator void schrieb:
Ich hab mir für den Fall einen allgemeinen Smart Pointer geschrieben, der automatisch auf 0 gesetzt wird, wenn das angepointerte Objekt freigegeben wird (das dafür allerdings von einer bestimmten Klasse abgeleitet sein muss). Das ist zwar etwas allgemeiner und deswegen vermutlich nicht ganz so effizient wie deine Lösung, aber wenn ich ihn trotzdem mal posten soll, sag Bescheid. Er hat zwar nicht jedes erdenkliches Feature, _sollte_ aber immerhin sicher und einfach zu benutzen sein. Ich benutze für ein ungefähr ähnliches Problem eine Kombination aus diesem Pointer und boost::shared_ptr und bin soweit ziemlich zufrieden damit.
Hört sich auch interessant an!
Also wenn es dir nichts ausmacht, würde mich über den Code freuen!
-
Hi
Was passiert bei delete object? der destruktor von object wird aufgerufen und danach wird der speicher über operator delete freigegeben.
nun, bei delete this können also folgende fälle eintreten:1. das objekt liegt am stack oder im statischen speicher d. programms:
soweit ich weiß ist das löschen solcher objekte über delete nicht erlaubt, da sie
nicht mit new erschaffen wurden. sprich undefiniertes verhalten2. du greifst nach dem delete this noch auf irgendwelche nicht statischen elementvariablen zu. da diese aber nach dem delete zerstört sind, d.h. this ungültig ist, erzeugt das undefiniertes verhalten
wenn du 1 und 2 ausschließen kannst, dann verwende ruhigen gewissens delete this, gesetz dem fall, du findest keine andere lösung um das (design?)problem zu umgehen.
ein vorschlag:
vielleicht willst du das Lebewesen ja auch nur töten. dann reicht doch eine art "kill()" funktion, die es selbst aufruft und quasi eine leiche hinterlässt. das lebewesen informiert dann alle registrierten on_kill - Listener darüber, dass es getötet worden ist, und die entscheiden, was mit der leiche passiert
-
davie schrieb:
ein vorschlag:
vielleicht willst du das Lebewesen ja auch nur töten. dann reicht doch eine art "kill()" funktion, die es selbst aufruft und quasi eine leiche hinterlässt. das lebewesen informiert dann alle registrierten on_kill - Listener darüber, dass es getötet worden ist, und die entscheiden, was mit der leiche passiertDanke Davie erstmal für den Beitrag. Damit kann ich also sicher sein, dass ich wenigstens delete this aufrufen dürfte!
Die Idee mit der kill-Funktion/Leiche ist ja praktisch dasselbe wie meine Idee mit der Variable "dead", oder? Halte ich auch für sinnvoll. Werde mich wahrscheinlich an einer solchen Lösung versuchen.
Danke!
-
Das Problem mit toten/gelöschten Elementen in der Objektliste von Spielen o.ä. ist imho ein ziemlich interessantes. Die Variante, die sich ausschließlich auf das dead-Flag verlässt, finde ich jedenfalls fehlerträchtig. Ich weiß nicht, inwiefern deine Objekte interagieren sollen, aber wenn Objekt A sich merken will, dass es irgendeine Beziehung mit Objekt B eingeht, kommst du mit dem dead-Flag langsam in Bedrängnis. Da brauchst du dann irgendeine Art der Notifikation. Entweder irgendein eigenes System dafür oder eben das Ausnullen des Zeigers als Signal, dass das Objekt nicht mehr funktioniert. Ich habe Letzteres gewählt und dafür diese Klasse geschrieben:
http://rafb.net/paste/results/l1971219.html
(Hoffentlich habe ich das richtig zusammengepastet. Für bewährtere Lösungen bzw. einen von richtigen Profis geschriebenen safe_ptr wäre ich auch dankbar. Der hier kommt nichtmals sauber mit Mehrfachvererbung klar. Für ein paar Extra-Kindersicherungen kannst du auch noch die boost-Sachen wieder einkommentieren, wenn du die Lib installiert hast.)Ist den Boost-Smart-Pointern nachempfunden und sollte so funktionieren: Das angepointerte Objekt wird von safe_pointee abgeleitet und statt rohen Zeigern auf das Objekt verwendest du safe_ptr<Objekt>. Die werden nicht nur 0-initialisiert, über assert()s gesichert etc. sondern dann auch noch automatisch 0, wenn das Objekt freigegeben wurde (oder reset_pointers() aufruft). Hm ja. Irgendwie wird das Thema immer so schnell kompliziert und ich könnte Aufsätze darüber schreiben und vielleicht gehe ich an das Problem auch ein Bisschen zu sauber ran. Naja. Nacht.
-
Grundsätzlich ist ein delete this erlaubt und es ist auch klar, was danach passiert. Aber es eignet sich nur für freilaufende Objekte, es ist kein idealer Ansatz wenn man die Objekte irgendwo übergeordnet verwaltet.
Grundsätzlich kann man das Problem mit der Benachrichtigung aber auch in so einer Art lösen:
Vieh* matrix[4][4]; Vieh* Vieh::doLifeCycle() { if (isLifetimeExceeded()) { // stirb! delete this; return NULL; } else { // leben eat(); return this; } } matrix[0][0] = matrix[0][0]->doLifeCycle();
Das Objekt löscht sich selbst und liefert immer einen Zeiger auf den neuen Zelleninhalt zurück. Ist das Tier gestorben, liefert es eben einen NULL-Zeiger. Lebt es, so liefert es wieder sich selbst zurück. Damit wird die Struktur automatisch vom Ableben benachrichtigt.
Ist aber keine gute Empfehlung, wenn andere Tiere eine Beziehung zu diesem Tier aufgebaut haben, da diese Beziehung an einem Ende abgeschossen wird. Kann man so lösen, aber nur wenn es eine einzige Verwaltung der Objekte gibt.
Hat den Vorteil, daß man auch andere Objekte zurück liefern kann:
Vieh* Phoenix::doLifeCycle() { // Zeit für einen Neuen! delete this; return new Phoenix(); }
Man kann auch Finite-Statemachines auf diese Weise sehr schön implementieren.
-
*ausgrab*
Hab da mal noch ne Frage zu:wenn ich eine Methode habe, z.B.
char* c_foo::dosomething() { foo_a(); delete this; foo_b(); return irgendwas; }
Was würde aus diesem Block noch ausgeführt werden bevor das objekt zerstört wird? wird noch was zurückgegeben? oder bricht es direkt beim delete ab?
Wenn ich auf eine klassenvariable zugreife, ist diese danns chon zerstört, oder wartet das Programm noch auf das zurückkehren der funktion??(Grund: ich will eine liste bauen die komplett ohne steuerung durch eine andere klasse auskommt, aber bei bestimmten aktionen scheiter ich immer.)
-
Die Funktion wird komplett ausgeführt; der ausführbare Code bleibt von delete this unbeeinflusst. Man darf nach delete this nur nicht mehr auf Klassenvariablen zugreifen oder virtuelle Funktionen verwenden, da diese direkt von this abhängig sind. Nicht-virtuelle Funktionen dürften aber kein Problem darstellen.
-
zu delete this:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.14
"Im prinzip" darfst du nach dem delete this nicht mehr auf den Zeiger oder einen Member zugreifen.