Hallo, ich habe eine Klasse welche einige Daten auf dem Heap alloziert und die Zeiger in Arrays ablegt. Beim aufrufen des Destruktors wird der Speicher mit delete wieder freigegeben. Soweit so klar. Aus Performance Gründen habe ich aber noch weitere Orte, an denen ich Zeiger auf die Objekte ablegen muss. Wenn ich jetzt das Objekt lösche bleiben diese Zeiger ja erhalten und können wenn sie nicht genullt werden viel kaputt machen. Was gibt es denn für Methoden so etwas elegant zu lösen? Hatte überlegt in dem Objekt noch eine Liste zu führen mit Zeigern auf die Zeiger die beim Löschen zu nullen sind, aber das gibt dann ja einen ewigen Rattenschwanz. Jemand eine bessere Idee?
olli23 schrieb: > Wenn ich jetzt das Objekt lösche bleiben diese Zeiger ja erhalten und > können wenn sie nicht genullt werden viel kaputt machen. das versteht ich nicht. einmal muss der Speicherbereich gelöscht werden der mit new/malloc angefordert wurde, wenn weiter Zeiger vorhanden sind müssen die nicht noch mal gelöscht werden. Wenn sie in einer Liste sind, dann muss nur die Liste gelöscht werden. Aber was meinst du mit dem nullen?
Das klingt nach einer grundsätzlich verquasten Architektur. Wie kommen deine Zeiger denn überhaupt nach 'extern' (wo immer das sein mag)?
Die sozusagen "primitivste" oder auch naheliegendste Methode wäre meiner Meinung nach, die Verwaltung der Zeiger selbst in ein Objekt zu kapseln; und für jeden Zeiger einen Referenzierungszähler einzuführen. Der Grundgedanke ist dabei, das es nur einen Ort gibt, an dem die Zeiger gespeichert werden. Oder anders herum: Zeiger zu duplizieren (aus Performance-Gründen wie Du sagst) ist an sich eine schlechte Idee (relativ und zu einem gewissen Grad auch eine Meinungssache). Das jedenfalls Zeiger in mehreren Objekten verwendet werden widerspricht meiner Meinung nach dem Kapselungsprinzip. Entweder die obige "primitive Lösung" oder sonst eine (Vererbung, Interface-Methoden) die in das Objekt-Paradigma passt.
olli23 schrieb: > Aus Performance Gründen habe ich aber noch weitere Orte, an denen ich > Zeiger auf die Objekte ablegen muss. Warum? Und warum sollte der "andere" Code auf die Idee kommen wollen diese Kopien der Zeiger noch zu verwenden nachdem sich das ganze Programm doch schon darüber einig geworden ist daß die besagten Objekte auf dem Heap entsorgt (und somit offensichtlich gar nicht mehr gebraucht) werden? Bekommt dieser andere Teil das nicht mitgeteilt, oder kann er das nicht vorher erfragen?
:
Bearbeitet durch User
olli23 schrieb: > Hallo, > > ich habe eine Klasse welche einige Daten auf dem Heap alloziert und die > Zeiger in Arrays ablegt. Beim aufrufen des Destruktors wird der Speicher > mit delete wieder freigegeben. Soweit so klar. > > Aus Performance Gründen habe ich aber noch weitere Orte, an denen ich > Zeiger auf die Objekte ablegen muss. > > Wenn ich jetzt das Objekt lösche bleiben diese Zeiger ja erhalten und > können wenn sie nicht genullt werden viel kaputt machen. > > Was gibt es denn für Methoden so etwas elegant zu lösen? std::shared_ptr<> ist das Mittel der Wahl.
Wilhelm M. schrieb: > std::shared_ptr<> ist das Mittel der Wahl. nicht zwingend. Man muss sich nur selber klar sein, wem die Daten gehören. shared_ptr und recoucencoutner sind nicht immer sinnvoll wenn es um perfomance geht. (was hier ja scheinbar wichtig ist).
Peter II schrieb: > Wilhelm M. schrieb: >> std::shared_ptr<> ist das Mittel der Wahl. > > nicht zwingend. Man muss sich nur selber klar sein, wem die Daten > gehören. Und genau das scheint dem TO eben nicht klar zu sein. Im übrigen denke ich auch, dass er std::shared_ptr und std::weak_ptr braucht. > > shared_ptr und recoucencoutner sind nicht immer sinnvoll wenn es um > perfomance geht. (was hier ja scheinbar wichtig ist). Nicht notwendigerweise: einen leicht erhöhten Aufwand hat man nur beim Erzeugen der Objekte.
Vielen Dank für die vielen schnellen Antworten. nochmal etwas expliziter beschreiben das Problem: ich habe eine Baumartige Datenstruktur (mit mehren 100 Objekten). Beim anlegen der Baumstruktur wird der Speicher alloziert. Es gibt dort einige Objekte auf die ich sehr oft zugreifen muss in einer festgelegten Reihenfolge. Damit ich jetzt nicht jedes mal den kompletten Baum durchsuchen muss (was einen Großteil der Performance zerstören würde) sind Zeiger zu allen diesen Objekten die man oft braucht zusätzlich zu der Baumstruktur in einer Liste hinterlegt. Dann muss man nur einmal den Baum durchsuchen und in die Liste eintragen und danach nur noch die Liste abarbeiten. @wimalopaan: der shared_ptr sieht auf den ersten Blick gut aus. Das schaue ich mir mal an.
Wilhelm M. schrieb: > [...] > std::shared_ptr<> ist das Mittel der Wahl. Vermutlich ist das so, jedenfalls wenn das Problem tatsächlich aus Performance-Gründen anders nicht zu lösen ist. Der Ratschlag scheint mir jedenfalls sinnvoll. Mir schien aber das Problem mit der Frage zu sein, dass so wenig vom Kontext bekannt ist. Ein Anfänger bzw. jemand der auf so ein Problem das erste Mal stösst (aber ansonsten fortgeschritten ist) sollte meiner Meinung nach, eine eigene Lösung des Problems versuchen. Deswegen meine, im wesentlichen, Wiedergabe der Implementierung von shared_ptr ohne es ausdrücklich zu nennen. Er sollte aber auch noch einmal durchdenken, ob dieser Weg wirklich notwendig ist. Deswegen meine (relativierte) Kritik und der Rat es mit bisher bekannten Mitteln innerhalb der bekannten Teile des Paradigmas zu versuchen. Falls dem TO das Vorhandensein von std::shared_ptr lediglich zeitweise entfallen war, spricht sicher nichts dagegen. Falls aber nicht, sollte er sich wenigstens mal die Implementierung anschauen, würde ich sagen.
Deine Liste ist an sich nur ein Cache. Wenn du an den Originaldaten (dem Baum) etwas änderst, musst du nur den Cache invalidieren. In deinem Fall also einfach die Liste leeren und neu aufbauen (währenddessen musst du natürlich alle Nutzer der Liste kurz anhalten).
olli23 schrieb: > [...] > nochmal etwas expliziter beschreiben das Problem: > > ich habe eine Baumartige Datenstruktur (mit mehren 100 Objekten). Beim > anlegen der Baumstruktur wird der Speicher alloziert. > Es gibt dort einige Objekte auf die ich sehr oft zugreifen muss in einer > festgelegten Reihenfolge. > > Damit ich jetzt nicht jedes mal den kompletten Baum durchsuchen muss > (was einen Großteil der Performance zerstören würde) sind Zeiger zu > allen diesen Objekten die man oft braucht zusätzlich zu der Baumstruktur > in einer Liste hinterlegt. Dann muss man nur einmal den Baum durchsuchen > und in die Liste eintragen und danach nur noch die Liste abarbeiten. Dann scheinen mir meine Vorbehalte nicht unnötig gewesen zu sein. Ich hoffe nur, ich habe das alles richtig verstanden. Wenn Du ohnehin eine "Liste" hast, die prominente Blätter des Baums beinhalten, dann ist da ja schon die nötige Verwaltungsstruktur. Auf die greifst Du zu und irgendwann im Ablauf, hörst Du damit endgültig auf. Dann kannst Du Liste löschen - musst aber nicht die Zeiger auf die Blatt-Objekte löschen. Die müssten, formal, ja ihre eigenen Destruktoren haben, die aufgerufen werden, wenn der Baum wieder gelöscht wird. Du musst nur durch den Programmablauf sicherstellen, dass eines nach dem anderen geschieht. (Erst Liste löschen dann Baum).
In modernem C++ verzichtet man auf ein explizites new/delete. Deswegen std::unique_ptr bzw. std::shared_ptr zusammen mit den Helpern std::make_shared und std::make_unique. Diese beiden Zeigertype zeigen die Art der Eigentümershaft ganz klar an und man nichts mehr falsch machen. Ggf. braucht man std::weak_ptr, um einen Zeiger zu haben, der keine Eigentümerschaft ausdrückt, jedoch promoted werden kann zu einem SmartPointer. Rohe Zeiger werden nur noch als Zeiger ohne Eigentümerschaft verwendet bspw. als Iteratoren. Manchmal werden sogar die rohen Zeiger auch noch in ein Template verpackt, um ggf. ein delete auszuschließen. Natürlich steht es einem frei, auch so etwas wie einen managed-pointer wie etwa QPointer einzuführen. Braucht man aber wegen std::weak_ptr nicht wirklich.
Wilhelm M. schrieb: > In modernem C++ ... Bezieht sich das evtl. auf meinen Beitrag resp. meine Beiträge?
Das Problem ist hier doch aber eins, das nichts primär mit Pointern zu tun hat. Es gibt hier mehrere Indizes in dieselben Daten, ohne einen Mechanismus, diese mehreren Indizes konsistent zu halten. Das Pointerproblem ist nur ein Auswuchs davon. Die Lösung wäre imho, diese spezielle Datenstruktur in eine Klasse MyFancyMultiIndexedInMemoryDatabase o.ä. zu kapseln und dafür zu sorgen, dass sie nur über deren Methoden manipuliert werden kann, die dann dafür zuständig sind, alle Indizes zugleich so zu ändern, dass sie konsistent bleiben.
Theor schrieb: > Wilhelm M. schrieb: >> In modernem C++ ... > > Bezieht sich das evtl. auf meinen Beitrag resp. meine Beiträge? Es scheint jedenfalls so und würde inhaltlich passen. Ich wollte mich auch eigentlich nur bedanken, Wilhelm.
der mechatroniker schrieb: > Das Problem ist hier doch aber eins, das nichts primär mit Pointern zu > tun hat. Es gibt hier mehrere Indizes in dieselben Daten, ohne einen > Mechanismus, diese mehreren Indizes konsistent zu halten. Das > Pointerproblem ist nur ein Auswuchs davon. > > Die Lösung wäre imho, diese spezielle Datenstruktur in eine Klasse > MyFancyMultiIndexedInMemoryDatabase o.ä. zu kapseln und dafür zu sorgen, > dass sie nur über deren Methoden manipuliert werden kann, die dann dafür > zuständig sind, alle Indizes zugleich so zu ändern, dass sie konsistent > bleiben. Letztlich kann man SmartPointer als genau das auffassen ...
Theor schrieb: > Theor schrieb: >> Wilhelm M. schrieb: >>> In modernem C++ ... >> >> Bezieht sich das evtl. auf meinen Beitrag resp. meine Beiträge? Ja, wer hier mitdiskutiert, läuft Gefahr ... > > Es scheint jedenfalls so und würde inhaltlich passen. > > Ich wollte mich auch eigentlich nur bedanken, Wilhelm. de nada
Wilhelm M. schrieb: > Theor schrieb: >> Theor schrieb: >>> Wilhelm M. schrieb: >>>> In modernem C++ ... >>> >>> Bezieht sich das evtl. auf meinen Beitrag resp. meine Beiträge? > > Ja, wer hier mitdiskutiert, läuft Gefahr ... ..., dass er angesprochen wird, ohne das sein Name genannt wird. :-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.