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 mittypeinfo.h
. Aber auch das funktioniert nicht, da ich denvoid*
-Pointer ja caste undtypeid()
mir entweder erzählt, dass ich einenvoid*
-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öglichesSIGSEGV
auszulösen (in dem eine Methode der Klasse über den gecasteten Pointer aufrufe, ohne vorher auf Gültigkeit zu prüfen und beiSIGSEGV
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.
-
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 vonMyClass
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.
-
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.
-
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).