Erkennen ob ein das Objekt eines Pointers noch existiert

  • Hi!


    Hätte mal eine Frage an die C++-Profis hier:
    Ist es irgendwie möglich (ev. auch mit "schmutzigen Tricks"), dass man feststellt ob das Objetk, auf das ein Pointer verweist, noch existiert?


    Konkret, habe ich einen Pointer der auf ein Timerobjekt verweist. Ich kann leider nicht direkt mitbekommen ob das Objekt gelöscht wird, deshalb könnten beim Versuch auf das Objekt zuzugreifen Fehler auftreten. Kann man das irgendwie abfangen?


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Hi!


    Danke euch für eure Antworten. try/catch hatte ich auch zu erst gesehen und dachte das ist die Lösung, allerdings muss man hier auch wieder irgendwie checken ob ein fehler auftritt und dann einen Fehler auswerfen (throw).
    Da kann man also leider keinen Code reinschreiben der ev. funzt und dann das Ergebnis abfangen.


    In dem Artikel habe ich leider auch nichts finden können ...


    Leider sehr ernüchternd ... muss mal darüber nachdenken wie ich das lösen/umgehen kann. Hier wäre so eine "on error goto"-Syntax wie bei VB wirklich praktisch. ;D


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Hi,


    Zitat

    Original von Brougs78
    Leider sehr ernüchternd ... muss mal darüber nachdenken wie ich das lösen/umgehen kann. Hier wäre so eine "on error goto"-Syntax wie bei VB wirklich praktisch. ;D


    Das macht doch speziell try/catch(...), es fängt einfach alles, die Klammer mit drei Punkten sind absicht...


    Also z.B.


    Code
    try {
      if(ptr != NULL)
         ptr->foo()
    } catch(...) {
      ptr = NULL;
    }


    Vielleicht hilft rtti noch :

    Code
    if (dynamic_cast<cTimer*>(a) != NULL)



    am saubersten ist trotzdem ein Smartpointer, bzw. einfach im Destruktor des Pointerobjekt eine Cleanuproutine ...
    Andreas

  • Ohne weiteres ist so eine Überwachung nicht möglich, da in C++ ein Pointer auf ein Objekt nun mal nur eine Speicheradresse ist. Einige Fehlertests sind möglich (Speicher vergeben, Typprüfung des Objekts etc.), aber das sind nur Indizien, keine verlässlichen Tests.


    Denkbar wäre eine Implementierung von intelligenten Pointern, die sich wie normale Pointer verhalten, aber als Objekt-Template implementiert sind. Dazu gehört eine Basisklasse, die in die eigentlichen Objekte eingeerbt wird.
    Die Basisklasse und der intelligente Zeiger bilden ein Team: Der Zeiger registriert sich während seiner Lebenszeit beim Objekt, und das Objekt löscht im Gegenzug alle registrierten Zeiger, wenn seine Lebenszeit zu Ende geht. (Bei Multithreaded-Programmen kann das natürlich fatale Nebenwirkungen haben, aber in solchen Situationen musst du dich sowieso um exklusiven Zugriff bemühen.)


    In der Praxis lohnt der Aufwand meistens nicht, es ist einfacher, im großen Bogen drum herum zu programmieren. Versuche, den Zeiger nicht so lange zu halten, dass jemand anderes das Objekt löschen kann. Besorg dir einen neuen Zeiger, wenn du ihn brauchst.


    Gruß,


    Udo

  • Hi!


    Also ich hab das jetzt nochmal mit try/catch probiert:


    Allerdings wird "Timer weg" nie ausgegeben, also wird der Fehler nicht abgefangen. Die StartTime wird zwar nur noch für weniger Timer ausgegen, also nicht für den gelöschten, aber irgendwie wird der Fehler nicht abgefangen bzw. der catch-Teil wird nicht durchgeführt.


    Ich hatte jetzt eine andere Lösung in der ich einfach die aktuelle Timerliste durchgehe und nur den Timerpointer vergleiche. Wenn ich ihn finde, dann kann ich davon ausgehen dass es eben den Timer noch gibt. Ist halt auch nicht die saubere und sichere Lösung obwohl es für meinen Zweck wohl funktionieren würde.


    Die saubere Lösung mit intelligenten Pointern kann ich leider nicht umsetzen, da ich ja VDR nicht patchen will.


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

    Einmal editiert, zuletzt von Brougs78 ()

  • Das obrige Beispiel von try/catch fängt nur seqfault's


    Ist ja alles relativ, ein Pointer ist nur eine Zahl von einer Speicheradresse, ab der die Datenstruktur deinen Timer liegt, beim freigeben des Speicher wird dieser ja nicht automatisch gelöscht, sondern nur für ungenutzt erklärt, bis die nächste Speicheranforderung diesen Speicherbereich neu zuweist. Und jetzt an der Speicheradresse auf die Pointer zeigt jetzt die andere Daten enthält. Möglicherweise sogar einen anderen Timer ;)
    Aber meistens zeigt die Pointer mitten in eine andere Datenstruktur.
    Wenn der Timer nur numerische Daten enthält, fällt der Unterschied nur durch wirre Daten auf.


    Deshalb als Lösungvorschlag, einfach per lookup überprüfen ob dein Timerpointer noch in der Liste der verhandenen Timer enthalten ist.



    z.B. mit cTimer *cTimers::GetTimer(cTimer *Timer)


    Andreas

  • Wenn du den Typ des Objekts kennst, kannst du doch mit


    typ* meintyp = NULL;
    meintyp =dynamic_cast<typ*>(originalpointer);


    if (meintyp) cout << "Juhuuuu, det geht";


    gucken, ob es noch da ist, oder bin ich auf dem holzigen Weg?


    Also in deinem Fall das timer-objekt dynamic_casten auf eine neue Zeigervariable? Sollte es vorher gelöscht worden sein, müsste das doch "irgendwie" scheitern, oder?



    PS: Wenn der Timer gelöscht, aber immer noch korrekt da ist, müsstest du ihn natürlich auch noch extra validieren, gegen die Timerliste z.b.


    Der vorgelagerte Typtest würde allerdings verhindern, dass du dem armen VDR laufend "irgendnen Müll" zu fressen gibst 8)

    This is a .44 Magnum, the most powerful handgun in the world. It can take your head clean off. You've got to ask yourself one question, Do I feel lucky?
    easyvdr 0.9a2 - TT-DVB-S2-6400 - ASUS AT3IONT-I deluxe - Atom 330 - 1,5TB WD EADS - Denon 1910 - Toshiba 42X3030D - Harmony 700

    3 Mal editiert, zuletzt von s_herzog ()

  • Hi!


    Ok, Hulk du hast gewonnen, mit

    Code
    return (Timers.GetTimer(timer) == NULL) ? NULL : timer;


    passiert jetzt genau das was ich wollte. :]
    Und so einfach. ;D


    Irgendwie kapier ich jetzt aber garnicht warum das funzt. Denn VDR greift ja dann auch auf die Eigenschaften des Timers zu und müsste dann ja auch einen "Speicherzugrifffehler" liefern da der ja nicht mehr da ist ...


    Hier der Code aus VDR:

    Code
    cTimer *cTimers::GetTimer(cTimer *Timer)
    {
      for (cTimer *ti = First(); ti; ti = Next(ti)) {
          if (ti->Channel() == Timer->Channel() && ti->Day() == Timer->Day() && ti->Start() == Timer->Start() && ti->Stop() == Timer->Stop())
             return ti;
          }
      return NULL;
    }


    Danke an alle. Übrigens der dynamic_cast führt leider auch zu einer "Speicherzugrifffsfehler".


    Gruß,
    Andreas

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Na, wenn Du ganz sicher gehen willst, überprüfst Du nicht nur den Inhalt sondern auch den Pointer selber :



    Cu,
    Andreas

  • Wie schon gesagt, es kann keinen sicheren Weg geben, um einen Pointer auf Lebendigkeit zu testen. Im schlimmsten Fall gehort der referenzierte Speicher bereits einem ganz anderen Objekt oder ganz anderen Daten, und dann kann ein Zugriff nahezu beliebigen Unfug bewirken. Auch ein dynamic_cast hilft da nicht mehr.


    Eigentlich ergibt sich aber doch aus GetTimer() von selbst die optimale Vorgehensweise:


    Leg vom Timer eine Komplettkopie an, den dazu nötigen Zuweisungsoperator gibts doch:


    cTimer Remember = *timer;


    Später, wenn du den Timer wieder brauchst, suchst du ihn einfach:


    cTimer *timer = Timers.GetTimer(&Remember);


    Ich denke, das ist der Weg, den Klaus für sowas vorgesehen hat. Den alten Zeiger wieder in GetTimer hinein werfen, das funktioniert natürlich nur, so lange der alte Timer noch zufällig an der Speicheradresse steht. Es muss schon eine Kopie sein.


    Gruß,


    Udo

  • Hi!


    Hmm ich muss aber immer mit aktuellen Daten arbeiten, weshalb da eigentlich keine Kopien verwenden kann.


    Ev. ist mein voriger Ansatz doch der sicherste, in dem ich einfach die Timer durchgehe und Suche ob ich den Pointer (also nur den Verweis) noch finde. Wenn ein Timer weg ist, dann werde ich auch keinen Timer mit der Speicheradresse mehr finden. Und wärend eines VDR-Lebens wird ja der Speicherbereich der Timer nicht verschoben oder? Oder macht das der Kernel ev.?


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Zitat

    Original von Brougs78
    Ev. ist mein voriger Ansatz doch der sicherste, in dem ich einfach die Timer durchgehe und Suche ob ich den Pointer (also nur den Verweis) noch finde.


    Ja. Beachte bitte dass Timer nur im Vordergrund-Thread des VDR bearbeitet werden sollten, da die Klasse keine Locking-Mechanismen (anders als z.B. Channels, die auch im EPG-Thread modifiziert werden) implementiert. Anderenfalls könnte es sein dass Du den Timer gerade benutzt, während er Dir per SVDRP, OSD oder weil er abgelaufen ist "unterm Hintern" weggelöscht wird.


    Zitat

    Wenn ein Timer weg ist, dann werde ich auch keinen Timer mit der Speicheradresse mehr finden. Und wärend eines VDR-Lebens wird ja der Speicherbereich der Timer nicht verschoben oder?


    Korrekt.


    Zitat

    Oder macht das der Kernel ev.?


    Nein. Eine solche Verschiebung tritt nur auf wenn VDR intern den Timer neu allokiert und kopiert. Das passiert aber nur wenn der Timer editiert wird (hier wird eine Kopie editiert und nach dem Editiervorgang ins Original zurückkopiert), ist also für Dich unerheblich.

  • Hi!


    Danke für die Infos. Das mit dem Vodergrund-Thread und Timer-Editieren habe ich auch schon mit Klaus abgesprochen. Derzeit gibt es ja die IncBeeingEditted und DecBeeingEditted (oder so ähnlich) und die beiden Methoden werden ja auch in SVDRP verwendet um das ganze halbwegs sicher zu machen. Klaus meinte aber auch dass er da mal ev. eine wirklich threadsichere Variante machen möchte.


    Bis dahin muss man eben im Vordergrund-Prozess sagen dass man was an den Timern editiert damit kein anderer dazwischenpfuscht. Wenn man in einem Thread arbeitet muss man eben darauf achten dass nicht gerade edtiert wird bzw. die SVDRP-Schnittstelle nutzen (die das gleich macht).


    Gruß,
    Brougs78

    - -- --- ================================================================ --- -- -
    Antec Fusion, Intel E5200, Asus P5N7A-VM (VDPAU), DD CineS2 v6 + DD DuoFlex CI // yavdr-0.6.1
    - -- --- ================================================================ --- -- -

  • Zitat

    Original von Brougs78
    Danke für die Infos. Das mit dem Vodergrund-Thread und Timer-Editieren habe ich auch schon mit Klaus abgesprochen. Derzeit gibt es ja die IncBeeingEditted und DecBeeingEditted (oder so ähnlich) und die beiden Methoden werden ja auch in SVDRP verwendet um das ganze halbwegs sicher zu machen. Klaus meinte aber auch dass er da mal ev. eine wirklich threadsichere Variante machen möchte.


    Da SVDRP selbst im Vordergrund-Thread abläuft, ist das nicht wirklich eine Gefahr :), und Inc-/DecBeingEdited sind auch nicht wirklich Thread-Safe (hier wird nicht mit Mutexen sondern mit einfachen Zählern gearbeitet). Sie sollen den VDR nur vor Torheiten bewahren, wenn während des Vordergrund-Threads das Menü "Timer bearbeiten" am OSD sichtbar ist.


    Zitat

    Bis dahin muss man eben im Vordergrund-Prozess sagen dass man was an den Timern editiert damit kein anderer dazwischenpfuscht. Wenn man in einem Thread arbeitet muss man eben darauf achten dass nicht gerade edtiert wird bzw. die SVDRP-Schnittstelle nutzen (die das gleich macht).


    Sollte für eine Alltagsanwendung sicher vorerst gehen, da ich nicht damit rechne, dass mehrere User parallel per OSD, SVDRP und per Thread in einem Plugin die Timerliste befeuern :)


    Für absolute Sicherheit sorgt allerdings trotz allem nur ein echtes Locking :]

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!