Ich habe die folgenden - verwandten - Fragen untersucht, und keiner von ihnen scheint mein genaues Problem zu adressieren: one, two, three.Ist die Verwendung von reinterpret_cast auf unterschiedlich qualifizierten Strukturelementen sicher?
Ich schreibe eine Sammlung von denen die Elemente (Schlüssel-Wert-Paare) zusammen mit einigen Buchhaltungsinformationen gespeichert sind:
struct Element {
Key key;
Value value;
int flags;
};
std::vector<Element> elements;
(Der Einfachheit halber wird angenommen, dass beide Key
und Value
Standard-Layout-Typen sind Die Sammlung wird sowieso nicht mit anderen Typen verwendet.)
Um Iterator-basierten Zugriff zu unterstützen, habe ich Iteratoren geschrieben, die operator->
und überschreiben, um dem Benutzer einen Zeiger bzw. eine Referenz zurückzugeben , t o das Schlüssel-Wert-Paar. Aufgrund der Art der Sammlung darf der Benutzer den zurückgegebenen Schlüssel jedoch nie ändern. Aus diesem Grund habe ich eine KeyValuePair
Struktur erklärt:
struct KeyValuePair {
const Key key;
Value value;
};
Und habe ich operator->
auf dem Iterator wie folgt umgesetzt:
struct iterator {
size_t index;
KeyValuePair *operator->() {
return reinterpret_cast<KeyValuePair *>(&elements[index]);
}
};
Meine Frage ist: ist diese Verwendung von reinterpret_cast
wohldefinierten oder ruft es undefiniertes Verhalten auf? Ich habe versucht, relevante Teile der Norm zu interpretieren und untersucht Antworten auf Fragen zu ähnlichen Problemen, jedoch scheiterte ich von ihnen eine endgültige Schlussfolgerung zu ziehen, weil ...:
- die beiden Strukturtypen teilen einige erste Datenelemente (nämlich
key
undvalue
), die sich nur inconst
-Identifikation unterscheiden; - Der Standard besagt nicht explizit, dass
T
undcv T
Layout-kompatibel sind, aber es gibt auch keine Umkehrung; fordert außerdem, dass sie dieselben Repräsentations- und Ausrichtungsanforderungen haben sollten; - Zwei Standardlayout-Klassentypen haben eine gemeinsame Anfangssequenz, wenn die ersten, jedoch viele Mitglieder Layout-kompatible Typen haben;
- für Union-Typen, die Mitglieder des Klassentyps enthalten, die eine gemeinsame Anfangssequenz teilen, ist es erlaubt, die Mitglieder einer solchen Anfangssequenz unter Verwendung eines der Union-Mitglieder zu untersuchen (9.2p18). - Es gibt keine ähnliche explizite Garantie, die über
reinterpret_cast
ed pointer-to-structs gemacht wird, die eine gemeinsame Anfangssequenz teilen. - es ist jedoch garantiert, dass ein Pointer-to-struct auf sein Anfangselement zeigt (9.2p19).
nur diese Informationen verwenden, fand ich es unmöglich, ob die Element
und KeyValuePair
structs eine gemeinsame Anfangssequenz teilen abzuleiten, oder irgendetwas anderes gemeinsam haben, dass meine reinterpret_cast
rechtfertigen würde.
Nebenbei, wenn Sie denken, mit reinterpret_cast
für diesen Zweck ist unangemessen, und ich bin wirklich vor einem XY-Problem und daher sollte ich einfach etwas anderes tun, um mein Ziel zu erreichen, lassen Sie es mich wissen.
Fragen Sie nach einem [Tag: Sprachanwalts] Urteil? Funktioniert es eigentlich? 'reininterpret_cast' ist fast immer der falsche Ansatz, sollte eine' const_cast' nicht gut für das funktionieren, was Sie behaupten? –
@ πάνταῥεῖ Ja, ich bitte um ein Sprach-Anwalt-Urteil. ** Ich kann unmöglich sagen, ob es tatsächlich funktioniert ** oder es scheint nur "zu funktionieren", da ich nicht weiß, ob es undefiniertes Verhalten aufruft. Ich weiß nicht, ob "const_cast" in diesem Fall funktionieren sollte, aber lassen Sie es mich versuchen - es ist jedoch immer noch nicht klar, ob "const_cast" das Kompilieren bedeutet, dass dies gut definiert ist. –
_ "aber, ob const_cast kompilieren würde bedeuten, dass dies gut definiert ist." _ Natürlich denke ich, dass das der Zweck ist. Die Verwendung von 'reininterpret_cast' kann nichts garantieren. –