Typ eines Pointers (auf eine Klasse) ermitteln



  • Ich habe bereits verschiedene Varianten versucht, aber es funktioniert alles nicht so wirklich. Meine Absicht ist es, einen Pointer zu einer Klasseninstanz zu casten und danach noch zu prüfen, ob das auch tatsächlich ein Pointer auf die Klasse war, um ein SIGSEGV zu verhindern.

    Meine erste Variante war per dynamic_cast. Jedoch wurde auch alles als gültig durchgewunken, was die gleiche Menge oder weniger Speicher belegte.
    Danach versuchte ich es mit typeinfo.h . Aber auch das funktioniert nicht, da ich den void* -Pointer ja caste und typeid() mir entweder erzählt, dass ich einen void* -Pointer (wenn ohne Cast) habe oder den "richtigen" Typ annimmt (aufgrund des Casts) auch wenn ich bspw. NULL gecastet hatte.

    Ich versuchte auch, via signal.h ein mögliches SIGSEGV auszulösen (in dem eine Methode der Klasse über den gecasteten Pointer aufrufe, ohne vorher auf Gültigkeit zu prüfen und bei SIGSEGV ein bool zu setzen) und das Signal an sich einfach zu ignorieren, jedoch ist auch das nicht gelungen.

    Als Beispiel:

    MyClass toVoid;
    void* pointer = &toVoid;
    
    [...] /* hier könnte pointer sich ändern, toVoid ist auf jeden Fall bereits ungültig */
    
    MyClass *mc = (MyClass*) pointer;
    if (/* mc == MyClass */) {
        // verwende den Pointer
    } else {
        // mache was anderes
    }
    


  • /* hier könnte pointer sich ändern, toVoid ist auf jeden Fall bereits ungültig */
    

    Dann ist auch die Adresse ungültig und alles weitere erübrigt sich.


  • Mod

    Die Frage, ob sich an einer bestimmten Stelle des Speichers ein Objekt eines bestimmten Typs befindet oder nicht, ist allgemein nicht durch die Untersuchung des Speichers selbst herauszufinden, da sie allein durch die Reihenfolge der abgearbeiteten Anweisungen bestimmt ist.
    Eine qualifizierte Ausnahme dazu besteht nur im Fall von polymorphen Objekten i.V.m. dynamic_cast, aber auch dann ist Voraussetzung, dass der Programmierer über die Existenz des polymorphen Objektes nicht lügt.

    Hinzu kommt, dass in den meisten Fällen der Zeiger auf Objekte, die zerstört wurden, nicht mehr auf einen bestimmte Stelle zeigt, und damit bereits der Versuch, Speicher zu untersuchen, scheitern muss.



  • Guter Einwand, das habe ich falsch dargestellt. So müsste es dann richtig sein:

    MyClass *toVoid = new MyClass;
    void* pointer = toVoid; // Kopie von toVoid
    
    [...] /* hier könnte pointer sich ändern, toVoid ist auf jeden Fall bereits ungültig */
    
    MyClass *mc = (MyClass*) pointer;
    if (/* mc == MyClass */) {
        // verwende den Pointer
    } else {
        // mache was anderes
    }
    

    @camper: Also MyClass hat ein paar virtuelle Methoden, die auch an andere Klassen vererbt werden. Mit der Existenz verstehe ich nicht ganz. Muss ich also zu hundert Prozent wissen, dass pointer noch auf ein Objekt von MyClass zeigt? Weil dann wäre das ja genau der Fall, der bei mir nicht zutrifft.



  • void* ist eine blöde Idee. Du musst wissen, was drin steht, um es wieder in den passenden Typ zu casten. Möglicherweise wäre boost::any eine Lösung.



  • manni66 schrieb:

    void* ist eine blöde Idee.

    Da ist mir die Idee gekommen, dass in einem LONG_PTR zu speichern.

    #define LONG_IS_MYCLASS    1
    
    MyClass *toVoid = new MyClass;
    LONG_PTR pointer = MAKELONG (toVoid, LONG_IS_MYCLASS);
    
    [...] /* hier könnte pointer sich ändern, toVoid ist auf jeden Fall bereits ungültig */
    
    if (HIWORD (pointer) == LONG_IS_MYCLASS) {
        MyClass *mc = (MyClass*) LOWORD (pointer);
    } else {
        // mache was anderes
    }
    

    Wäre das (in der Form unter Windows) gültig? Bzw. ginge das auch plattformunabhängig?



  • Nein. Nein.


  • Mod

    Hinzu kommt, dass in den meisten Fällen der Zeiger auf Objekte, die zerstört wurden, nicht mehr auf einen bestimmte Stelle zeigt, […]

    Was meinst du mit "zeigen" und "Stelle"? Nachdem das Objekt zerstört worden ist, ist "zeigen" (welches als Gegenstück des normativen "point" fungiert) zwar spätestens seit N4430 tatsächlich das falsche Verb, aber du hast bestimmt die Repräsentierung der Adresse der region of storage gemeint, und die ist noch gegeben solange der Speicher gültig ist (i.e. die duration der region of storage währt) - schließlich können wir ein neues Objekt konstruieren, o.ä.
    Sobald der Speicher ungültig wird, hat jeder entsprechende Zeiger einen ungültigen Wert, und er zeigt nicht und repräsentiert auch keine Adresse.



  • Das was Du vorhast funktioniert wenn Du Deine Klassen von einer gemeinsamen Vorfahrklasse ableitest. Einen Zeiger auf diese Vorfahrklasse kannst Du dann per dynamic_cast casten und es verhält sich so wie Du es erwartest.

    ABER: Die Notwendigkeit des Castens deutet in den allermeisten Fällen auf einen Designfehler hin.


  • Mod

    Arcoth schrieb:

    Hinzu kommt, dass in den meisten Fällen der Zeiger auf Objekte, die zerstört wurden, nicht mehr auf einen bestimmte Stelle zeigt, […]

    Was meinst du mit "zeigen" und "Stelle"? Nachdem das Objekt zerstört worden ist, ist "zeigen" (welches als Gegenstück des normativen "point" fungiert) zwar spätestens seit N4430 tatsächlich das falsche Verb, aber du hast bestimmt die Repräsentierung der Adresse der region of storage gemeint, und die ist noch gegeben solange der Speicher gültig ist (i.e. die duration der region of storage währt) - schließlich können wir ein neues Objekt konstruieren, o.ä.
    Sobald der Speicher ungültig wird, hat jeder entsprechende Zeiger einen ungültigen Wert, und er zeigt nicht und repräsentiert auch keine Adresse.

    Ich meine mit meistens, dass auf die Zerstörung eines Objektes typischerweise die Freigabe des entsprechenden Speichers unmittelbar folgt (delete, automatische Objekte).



  • Danke für die Anregungen. Da werde ich dann wohl eine andere Möglichkeit finden müssen ( boost::any wurde ja bspw. genannt).


Log in to reply