C ++: sichere Weise eine ganze Zahl in einen Zeiger zu werfen
-
11-09-2019 - |
Frage
Ich brauche einen integralen Typ zu konvertieren, die eine Adresse auf den tatsächlichen Zeigertyp enthält. Ich konnte verwenden reinterpret_cast wie folgt:
MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);
Dies ist jedoch führt keine Laufzeit überprüft, ob die betreffende Adresse tatsächlich ein MyClass Objekt enthält. Ich möchte wissen, ob es einen Nutzen ist in erster zu einer void * Umwandlung (mit reinterpret_cast) und dann auf das Ergebnis mit dynamic_cast. Wie folgt aus:
void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);
Gibt es einen Vorteil in der zweiten Methode?
Lösung
Geben Sie auf dynamic_cast
Überprüfung auf unterschiedliche Weise durch verschiedene C ++ Implementierungen umgesetzt wird; wenn Sie eine Antwort für Ihre spezifische Implementierung möchten, sollten Sie erwähnen, welche Implementierung Sie verwenden. Der einzige Weg, die Frage im allgemeinen zu beantworten ist der ISO-Norm C ++ zu verweisen.
Durch meine Lektüre der Norm, ruft dynamic_cast
auf einem void-Zeiger ist illegal:
dynamic_cast<T>(v)
„Wenn T ein Zeigertyp ist, v ist ein R-Wert eines Zeigers sein Klassentyp zu vervollständigen“
(von 5.2.7.2 der Norm ISO ++ C). void
ist kein vollständiger Klasse-Typ, so der Ausdruck ist illegal.
Interessanterweise wird die Art werfen darf einen void-Zeiger sein, d.
void * foo = dynamic_cast<void *>(some_pointer);
In diesem Fall ist die dynamic_cast
immer erfolgreich ist, und der sich ergebende Wert ist ein Zeiger auf den meisten abgeleitetes Objekt, auf das durch v
.
Andere Tipps
Nein, es gibt keinen besonderen Vorteil dabei. In dem Moment, Sie reinterpret_cast
verwenden, sind alle Wetten ab. Es liegt an Ihnen, um sicherzustellen, dass die Besetzung gültig ist.
Eigentlich kein ernsthafter Vorteil. Wenn die void * zeigt auf etwas, das nicht ein Zeiger auf ein polymorphes Objekt ist, dass Sie in undefiniertes Verhalten führen (in der Regel einer Zugriffsverletzung) sofort.
Der sichere Weg ist eine Aufzeichnung aller Live-MyClass Objekte zu halten. Es ist am besten, diese Aufzeichnung in einem std::set<void*>
zu halten, was bedeutet, dass Sie leicht hinzufügen, entfernen und Testelemente.
Der Grund, sie als void*
s zum Speichern ist, dass Sie nicht nastyness riskieren wie unaligned MyClass*
Zeiger aus dem ganzen Zahl zu schaffen.
-
Zunächst einmal „neu zu interpretieren“
int
zuvoid *
ist eine schlechte Idee. Wennsizeof(int)
4 undsizeof(void *)
ist 8 (64x-System) ist schlecht ausgebildet sind. -
Darüber hinaus
dynamic_cast
gilt nur für den Fall der polymorphen Klassen.
Option 1 ist die einzige (halb) portable / gültige Option.
Option 2: ist nicht gültig C ++ als dynamic_cast (void ist nicht erlaubt)
.Bei einer Implementierungsebene erfordert es Informationen aus dem Quelltyp eingeben, um den Zieltyp zu erhalten. Es gibt keine Möglichkeit (oder es kann keine Möglichkeit gegeben sein), um die Laufzeitquelle Typinformationen aus einer Lücke zu bekommen * so ist dies entweder nicht gültig.
dynamic_cast wird verwendet, um cas auf und ab der Typenhierarchie nicht von unbekannten Typen.
Als Seite beachten sollen Sie wahrscheinlich ungültig mit * anstatt einer ganzen Zahl mit einem nicht typisierten Zeiger zu speichern. Es gibt Potenzial für ein int nicht groß genug sein, um einen Zeiger zu speichern.
Der sicherste Weg, Zeiger in C ++ zu handhaben ist, sie typsicher zu handhaben. Das bedeutet:
- Nie speichern Zeiger in etwas anderes als ein Zeiger
- Vermeiden void-Zeiger
- Sie niemals passieren Verweise auf andere Prozesse
- betrachten weak_ptr wenn Sie Zeiger über Threads verwenden
Der Grund dafür ist: was Sie planen, unsicher zu tun ist, und kann vermieden werden, es sei denn, Sie (legacy?) Code unsicher mit Schnittstellen sind. In diesem Fall betrachtet MSalters' Antwort, aber bewusst sein, dass es immer noch ein Streit ist.
Wenn Sie sicher wissen, dass the_integer
Punkte auf einen bekannten Basisklasse (dh mindestens ein virtuelles Mitglied), da in der Tat könnte ein Vorteil sein: zu wissen, dass das Objekt einer bestimmten Klasse abgeleitet ist. Aber man müßte zuerst an Ihre Basisklasse reinterpret_cast
und dann die dynamic_cast
tun:
BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);
ein void*
in dynamic_cast
Verwendung ist nutzlos und einfach falsch. Sie können nicht dynamic_cast
verwenden um zu überprüfen, ob es an einer beliebigen Stelle im Speicher ein gültiges Objekt ist.
Sie sollten auch darauf achten, wenn Adressen in Nicht-Zeiger-Typ-Variablen zu speichern. Es gibt Architekturen, bei denen sizeof (void *)! = Sizeof (int), z.B. LP64.