unique_ptr und Lebenszeit



  • Ich möchte das ja gar nicht erklären, das würde für diesen Zweck wirklich zu weit führen. Ich wollte nur einige Worte zur Rechtfertigung dazu verlieren, dass ich eine solche Debug-Möglichkeit für sinnvoll halte, nachdem mir eine Grundsatzdiskussion während eines ganz anderen Themas aufgezwungen wurde. Ich hatte für mein ursprüngliches Anliegen genügend Kontext geliefert, der Sinn dahinter wurde dann mit Simpelbeispielen ins "Lächerliche" gezogen.

    Vielleicht würde mir für zukünftige Projekte noch ein Hinweis helfen, welche Alternativen es für GUI-Projekte gibt, die nicht ereignisbasiert funktionieren 😉 Oder eine bessere Alternative zu einer lockeren Interpretation von MVC (Ich könnte mir da manchmal die Haare raufen, dass man eben nicht immer alle Daten so einfach zur Verfügung hätte, wie man sie beim rumfrickeln gerne hätte).

    Aber das ist ja eine ganz andere Diskussion, die ich beizeiten mal unter einem anderen Thread eröffnen sollte.

    Ich wünsch' euch was!



  • Falls das Ursprungsproblem noch existiert hätte ich einen Lösungsvorschlag anzubieten. Da man dafür aber etwas ausholen muss, mache ich das OnDemand.

    Bei Interesse bitte nochmal in Kürze die Requirements posten. Beschreibungen wie Mischung von "weak_ptr, unique_ptr" ist nicht Zielführend.



  • Ich kann jetzt Deinem Ton nicht deutlich entnehmen, ob Dein Angebot konstruktiv oder sarkastisch ist.

    Das Anliegen war folgendes:
    Ein Paar aus Smart-Pointer-Klassen bei dem eine Klasse den Besitz der fraglichen dynamisch erzeugten Ressource darstellt, inklusive der Verwaltung der Lebenszeit und die andere Klasse einer Erlaubnis zur Verwendung inklusive der Möglichkeit, diesem die Rechte wieder zu entziehen, so dass ein Halter der vormaligen Erlaubnis diesen Entzug feststellen kann.

    Diese Klassen sollen nicht dazu verwendet werden, ein Softwaredesign darauf aufzubauen, sondern zuverlässig einen Fehler in der Implementierung aufzudecken, an stellen, an denen mein treuer Debugger zuvor gescheitert ist.



  • Mit anderen Worten: Du willst eine Referenz auch den unique_ptr?

    Mir ist nicht ganz klar wie genau du damit Fehler finden willst. Ich seh nur wie du damit neue Fehler erzeugen kannst die ansonsten gar nicht möglich wären...



  • Nein, keine Referenz auf den Smartpointer mit fraglichem Namen. Der besitzanzeigende Zeiger wird ja irgendwann mal zerstört und zerstört die von ihm verwaltete Ressource gleich mit. Dass dieses Ereignis stattgefunden hat, während noch andere Smartpointer von abweichendem Typ auf die fragliche Ressource verweisen, das sollen letztere zuverlässig herausfinden können, ohne "undefined behaviour" hervorzurufen. Es soll letzteren Zeigern aber nicht möglich sein, Einfluss auf die Lebenszeit zu nehmen.



  • Aber das findest du doch sowieso mit jedem Debugger heraus, warum dafür den Code unnötig kompliziert machen!?



  • Wie ich bereits geschrieben habe, hatte ich Fälle, bei denen es für meinen beschränkten Geist ein Akt war, die genaue Stelle des Fehlers aufzufinden, weil der Fehler ja zur Zeit der Zerstörung der Ressource stattfindet und nicht zur Zeit des Zugriffs auf die Ressource irgendwann danach, bei dem nichtmal zuverlässig sofort eine Ausnahme geworfen wird.





  • Eher soetwas: http://valgrind.org/
    Aber für Winkrücke gibts wohl leider nichts in die Richtung, denke ich.



  • Also ich bin kein Linux Experte, aber ich bezweifle dass valgrind bei diesem konkreten Problem viel helfen kann. Es geht nicht darum, memory leaks zu finden, oder rauszufinden wo ein kaputter Block allokiert wurde (das geht mit dem CRT Heap natürlich auch alles).



  • Decimad schrieb:

    Das Anliegen war folgendes:
    Ein Paar aus Smart-Pointer-Klassen bei dem eine Klasse den Besitz der fraglichen dynamisch erzeugten Ressource darstellt, inklusive der Verwaltung der Lebenszeit und die andere Klasse einer Erlaubnis zur Verwendung inklusive der Möglichkeit, diesem die Rechte wieder zu entziehen, so dass ein Halter der vormaligen Erlaubnis diesen Entzug feststellen kann.

    Mir klingt das eher nach einer CRTP-Proxy-Klasse die sich wie ein Pointer verhält und wo beispielsweise der operator::-> überladen ist.
    Je nach Kontext sagt man dazu auch Handle.

    Falls Ownership besteht hast du quasi ein rwHandle, falls du das Ownership nicht hast, eben nur roHandle.



  • Und wie findest du mit deinem Handle raus ob das referenzierte Objekt noch existiert?



  • _CrtIsValidHeapPointer springt an

    o Wenn der logische Fehler bereits "lange" zuvor gemacht wurde.
    o Wenn nicht in der Zwischenzeit eine Allozierung an der Stelle im Speicher auftrat (bin mir hier nicht so ganz sicher, ob die das nicht irgendwie bedacht haben, beim Debug-Heap).

    Wenn _CrtIsValidHeapPointer anspringt, würde die Dereferenzierung wahrscheinlich auch eine Ausnahme werfen (Da das so während des Debug-Laufs bestimmt irgendwie geprüft wird).



  • dot schrieb:

    Und wie findest du mit deinem Handle raus ob das referenzierte Objekt noch existiert?

    Dabei handelt es sich um ein lösbares Problem, bei entsprechenden Rahmenbedingungen.
    In den Systemen die ich kenne gibt es eine

    bool isValid() const;
    

    mit der man die Gültigkeit des Objekts abfragen kann.



  • Würde es nicht reichen einen Zähler einzuführen, der die Anzahl der unique_weak_ptrs speichert (im Konstruktor der weak_unique_ptrs + 1, im Destruktor -1) und dann dem unique_ptr eine eigene Deleter mitzugeben, der eine Exception schmeist wenn der Zähler nicht null ist? Man könnte die unique_weak_ptr auch noch in einer List speichern, um herauszufinden, welcher pointer noch darauf zugreift.



  • Also im Prinzip könnte die "Container"-Klasse auch Handles rausgeben.
    Aber ich gehe ja auch zum Herd und drehe am Knopf (naja, bei den neumodischen Teilen drücke ich), und sag dem Herd nicht "Drehen" während ich auf den offen sichtbaren Knopf deute.
    Wenn der Herd aber über Nacht geklaut und durch eine Atombombe mit einem Knopf an derselben Stelle ersetzt wird, dann drücke ich ja auch nicht mehr drauf, selbst wenn nach einer von dem Actionfilm abhängigen Zeit darauf aufmerksam gemacht würde, dass da was falsch lief. (Ich komme gerade vom Herd ;))

    @Phyax: Genau soetwas habe ich mir vorgestellt und bin noch am überlegen, ob ich mir das mal ausarbeite. Im Moment diskutiere ich hier erstmal nur mit 😉



  • Um was für einen Container geht es denn genau? Ich fürchte ohne konkrete Info kommen wir da nicht weiter...



  • Decimad schrieb:

    Also im Prinzip könnte die "Container"-Klasse auch Handles rausgeben.

    Genau das, damit bleibt der physikalische Besitz immer an dieser Stelle und "von außen" kann man als unique_ptr drauf zu greifen.



  • Es handelt sich hierbei um die Basisklasse der Knoten sowie den Asssoziationen zwischen allem im Datenmodell meines datenflussorientierten Messprogramms. Sowas wie Labview für Arme (oder sollte man sagen für noch ärmere?). Funktioniert inzwischen auch toll!
    Diese Knoten haben eine variable und vor allem dynamische Anzahl von Ein- und Ausgängen, welche von abgelittenen Klassen über die Basisklasse nach draußen veröffentlicht werden. Sie werden in einer Graph-Objekt aggregiert, welches auch die Verbindungen zwischen Ein- und Ausgängen verwaltet und alle Datenstrukturen up-to-date hält. Dieses Datenmodell visualisiert der Graph-View, der nach dem Observer-Muster synchron zum Modell bleibt. Mithilfe von Command-Objekten wird Einfluss auf das Modell genommen (Knoten erzeugen, löschen, bewegen, Verbindungen ziehen usw.).
    Während die Datenstrukturen und Klassenaufteilungen noch gewissermaßen im Fluss waren, habe ich bei gewissen Änderungen und Anpassungen einfach nicht die Regeln bezüglich der Lebenszeiten der einzelnen miteinander assoziierten Objekte beachtet, Observer-Benachrichtigungen vergessen, die ich mir zuvor überlegt habe oder ähnliches.

    Die schwer nachzuvollziehbaren Abstürze traten dann zumeist bei irgendwelchen Windows-Nachrichten-Einsprüngen auf, die Windows bei zB. leerer Warteschlangen durchführt. Dem Debugger fehlt dann der komplette Kontext, der diesen Nachrichtenaufruf auslöste, falls es denn überhaupt einen gibt. Der Fehler (Erzeugung einer inkosistenten Datenstruktur) aber wurde natürlich im logischen Sinne begangen, noch bevor der Prozess sich schlafen gelegt hat, zu dem der Kontext noch 1A klar war. Diesen Zeitpunkt möchte ich erwischen und er auch mich.



  • Nurf, ich stelle mir unter den Namen "Handle" nun aber sowas vor, was Windows rausgibt. Also irgendeine für mich untypisierte Zahl (sind wohl eher verkappte Zeiger), die ich bei Prozeduralen Zugriffen als Argument mit angebe.
    Wenn du Handles in einem anderen, mir gelegeneren, Sinn verstehst (Denn solche Aufrufe wie "node->GetOutputName(outputHandle)" oder noch extremer "graph.GetNodeOutputName(outputHandle)" möchte ich nicht haben), dann würde ich dich bitten, mir einmal Pseudo-Code zu bieten oder eine genaurere Beschreibung, damit wir uns hier über dasselbe unterhalten.


Anmelden zum Antworten