Frage

Ich lese ein Buch und ich finde, dass reinterpret_cast nicht direkt verwendet werden soll, sondern vielmehr Gießen mit static_cast void * in Kombination:

T1 * p1=...
void *pv=p1;
T2 * p2= static_cast<T2*>(pv);

Statt:

T1 * p1=...
T2 * p2= reinterpret_cast<T2*>(p1);

Allerdings kann ich keine Erklärung finden, warum dies besser als die direkte Besetzung. Ich wäre sehr dankbar, wenn jemand mir eine Erklärung geben kann, oder zeigen Sie mir die Antwort.

Vielen Dank im Voraus

P. S. Ich weiß, was reinterpret_cast für verwendet wird, aber ich sah nie, dass auf diese Weise verwendet wird,

War es hilfreich?

Lösung

Für die Typen, für das solcher Guss zulässig ist (zum Beispiel, wenn T1 ist ein POD-Typ und T2 ist unsigned char), der Ansatz mit static_cast gut definiert durch die Norm.

Auf der anderen Seite ist reinterpret_cast vollständig Implementierung definiert - die einzige Garantie, die Sie dafür bekommen, ist, dass Sie einen Zeiger Typen jeden anderen Zeigertyp gegossen und dann zurück, und Sie werden den ursprünglichen Wert erhalten; und auch können Sie einen Zeigertyp zu einem integralen Typ, der groß genug werfen einen Zeigerwert zu halten (die bei der Umsetzung variieren, und bestehen muss nicht), und werfen sie dann zurück, und Sie werden den ursprünglichen Wert.

Um genauer zu sein, wird ich zitiere nur die relevanten Teile der Norm, Hervorhebung wichtige Teile:

5.2.10 [expr.reinterpret.cast]:

  

Die Zuordnung von reinterpret_cast ausgeführt ist Implementierung definiert . [Anmerkung:. Es könnte, oder auch nicht, erzeugen eine Darstellung unterscheidet sich von dem ursprünglichen Wert] ... ein Zeiger auf ein Objekt kann explizit auf einen Zeiger auf ein Objekt von einem anderen Typ umgewandelt werden), außer dass ein R-Wert vom Typ umzuwandeln. „Zeiger auf T1“ den Typ „Zeiger auf T2“ (wobei T1 und T2 sind Objekttypen und wo die Ausrichtungsanforderungen von T2 nicht strenger als die von T1) und zurück in seinen ursprünglichen Typ ergibt den ursprünglichen Zeigerwert, das Ergebnis eines solchen Zeiger Umwandlung ist nicht spezifiziert .

So etwas wie folgt aus:

struct pod_t { int x; };
pod_t pod;
char* p = reinterpret_cast<char*>(&pod);
memset(p, 0, sizeof pod);

ist effektiv nicht näher bezeichnet.

zu erklären, warum static_cast Werke ein wenig komplizierter ist. Hier ist der obige Code verwenden static_cast neu geschrieben, die ich glaube, ist garantiert immer wie vorgesehen von dem Standard:

struct pod_t { int x; };
pod_t pod;
char* p = static_cast<char*>(static_cast<void*>(&pod));
memset(p, 0, sizeof pod);

Auch hier lassen Sie mich zitieren die Abschnitte der Norm, die zusammen mir führen zu dem Schluss, dass die oben sollte tragbar sein:

3,9 [basic.types]:

  

für jedes Objekt (andere als eine Basisklasse Subobjekt) des POD-Typ T, ob das Objekt einen gültigen Wert vom Typ T hält, die zu Grunde liegende Bytes (1.7), um das Objekt bilden, kann in eine Anordnung von kopiert char oder unsigned char. Wenn der Inhalt des Arrays von char oder unsigned char zurück in das Objekt kopiert wird, wird das Objekt anschließend den ursprünglichen Wert halten.

     

Die Objektdarstellung eines Objekts des Typs T ist die Sequenz von N unsigned char Objekte vom Objekt des Typs T aufgenommen, wobei N gleich sizeof (T).

3.9.2 [basic.compound]:

  

Objekte von cv-qualifiziert (3.9.3) oder cv-unqualifiziertem Typ void* (Zeiger auf void) können auf Objekte von unbekanntem Typ Punkt verwendet werden. Ein void* ist in der Lage, jedes Objekt Zeiger zu halten. A-cv cv-qualifiziert oder unqualifizierte (3.9.3) void* wird die gleiche Darstellung und Ausrichtungsanforderungen als cv-qualifiziert oder CV-unqualifizierten char* haben .

3.10 [basic.lval]:

  

Wenn ein Programm versucht, den gespeicherten Wert eines Objekts durch einen L-Wert von anderen zugreifen als einer der folgenden Typen ist das Verhalten nicht definiert):

     
      
  • ...
  •   
  • ein char oder unsigned char type .
  •   

4.10 [conv.ptr]:

  

rvalue des Typs „Zeiger auf cv T“, wobei T ein Objekttyp ist, kann zu einem R-Wert des Typs „Zeiger auf cv nichtig.“ Umgewandelt werden, das Ergebnis eines „Zeiger auf cv T“ a converting „ Zeiger auf cv Void“zeigt auf den Anfang der Speicherstelle, auf die das Objekt vom Typ T liegt, als ob das Objekt ein meisten abgeleitetes Objekt (1,8) vom Typ T ist (das heißt, nicht eine Basisklasse Subobjekt).

5.2.9 [expr.static.cast]:

  

Die Inverse von jeder Standard-Konvertierungssequenz (Abschnitt 4), andere als die L-Wert-zu-R-Wert (4,1), array-topointer (4.2), Funktions-to-Zeiger (4,3) und boolean (4,12) Konvertierungen kann explizit mit static_cast durchgeführt werden.

[EDIT] Auf der anderen Seite, haben wir dieses Juwel:

9.2 [class.mem] / 17:

  

Ein Zeiger auf eine POD-struct Objekt, in geeigneter Weise eine reinterpret_cast umgewandelt unter Verwendung, weist auf seiner Ausgangselement (oder, wenn das Element ein Bitfeld, dann an die Einheit, in der er sich befindet), und vice versa. [Anmerkung: Es könnte also seine unbenannte padding innerhalb eines POD-struct-Objekts, aber am Anfang nicht, wie erforderlich, geeignete Ausrichtung zu erreichen. ]

, die diese reinterpret_cast zwischen Zeiger zu implizieren scheint impliziert irgendwie „gleiche Adresse“. Stelle dir das vor.

Andere Tipps

Es gibt nicht den geringsten Zweifel, daß es die Absicht ist, dass beide Formen gut definiert sind, aber die Formulierung nicht, dass zu erfassen.

Beide Formen werden in der Praxis funktionieren.

reinterpret_cast ist expliziter über die Absicht und sollte bevorzugt werden.

Der wahre Grund für das so ist, weil, wie C ++ definiert Vererbung und wegen Mitglied Zeiger.

Mit C, Zeiger ist so ziemlich nur eine Adresse, wie es sein sollte. In C ++ ist es komplizierter zu sein, weil einige seiner Funktionen.

Die Mitglied Zeiger wirklich ein in eine Klasse versetzt, so werfen sie ist immer eine Katastrophe C-Stil verwendet wird.

Wenn Sie multiplizieren zwei virtuelle Objekte geerbt haben, die auch einige Betonteile haben, das ist auch eine Katastrophe für C-Stil. Dies ist der Fall in Mehrfachvererbung, die alle Probleme verursacht, obwohl, so dass Sie sollten nicht immer sowieso diese verwenden möchten.

Wirklich hoffentlich nie diese Fälle in erster Linie verwenden. Auch, wenn Sie eine Menge werfen, das ist ein weiteres Zeichen Sie vermasselt in in Ihrem Design.

Das einzige Mal, dass ich Gießen am Ende ist mit den Primitiven in den Bereichen C ++ entscheidet nicht die gleichen sind, aber wo sie offensichtlich sein müssen. Für aktuelle Objekte, Sie jederzeit etwas werfen wollen, starten Sie Ihren Entwurf in Frage zu stellen, weil Sie die meiste Zeit ‚Programmierung der Schnittstelle‘ sein sollte. Natürlich können Sie nicht ändern, wie 3rd-Party-APIs arbeiten, damit du immer nicht viel Auswahl haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top