Vorrang von Konvertierungsoperator & std::addressof
-
Ergänzung zu Werners Beitrag: Beim VC11 passt es.
-
cooky451 schrieb:
Offen gesagt verstehe ich nicht mal, wo da jetzt der Fehler ist?
Schau auf den Output. std::adressof und boost::adressof liefern verschiedene Werte (0x0012FF54 != 0x0012FF50), d.h. mindestens eine adressof-Funktion liefert einen Pointer, der nicht auf das Objekt zeigt; liegt also falsch.
std::adressof (MS VC10) liefert eben nicht den Pointer auf das Objekt sondern auf den char-member 'c_'.Passiert Dir das in einem Programm, wo dieser Pointer-Wert irgendwie weiter benutzt wird, so passiert alles mögliche, aber nicht was das Programm tun soll.
Gruß
Werner
-
Also wird die MS Implementierung wohl stupide die Referenz auf char& casten und davon die Addresse nehmen?
Was ist denn die sichere Variante?Btw müsste
template<typename T> T* addressof(T& v) { T* p = &v; return p; }nicht langen? Schließlich sind beide Referenzierungsoperatoren kein Match, da weder int** noch char& nach T* konvertiert werden können ... oder stoppt der Compiler dann anstatt als dritte Möglichkeit einfach den builtin-Operator zu verwenden, der einfach nur die Addresse des Objekts nimmt?
Edit: Ahh ... du hast ja nur einen Referenzierungsoperator definiert, der andere ist ja kein Castoperator ... nicht richtig gelesen.
-
Ethon schrieb:
Was ist denn die sichere Variante?
z.B. so
template <typename T> T* addressof(T& x) { return const_cast<T*>(reinterpret_cast<const volatile T*>(&reinterpret_cast<const volatile char&>(x))); }Ein kleiner Nachteil gegenüber dem eingebauten &-Operator besteht darin, dass addressof nicht constexpr sein kann.
-
camper schrieb:
Ethon schrieb:
Was ist denn die sichere Variante?
z.B. so
template <typename T> T* addressof(T& x) { return const_cast<T*>(reinterpret_cast<const volatile T*>(&reinterpret_cast<const volatile char&>(x))); }Ein kleiner Nachteil gegenüber dem eingebauten &-Operator besteht darin, dass addressof nicht constexpr sein kann.
Und warum stört hierbei nicht der Konvertierungsoperator?
operator char&() { return c_; }char& ist ja in char const volatile& konvertierbar.
-
reinterpret_cast führt niemals zum Aufruf von Konstruktoren oder Konvertierungsoperatoren.
-
camper schrieb:
reinterpret_cast führt niemals zum Aufruf von Konstruktoren oder Konvertierungsoperatoren.
Stimmt. Dann frage ich mich wie man es überhaupt falsch implementieren kann.

-
Ethon schrieb:
Stimmt. Dann frage ich mich wie man es überhaupt falsch implementieren kann.

VC10 schrieb:
template<class _Ty> inline _Ty * addressof(_Ty& _Val) { // return address of _Val return ((_Ty *) &(char&)_Val); }So kann man es falsch machen, Ethon
.VC11 schrieb:
template<class _Ty> inline _Ty *addressof(_Ty& _Val) _NOEXCEPT { // return address of _Val return (reinterpret_cast<_Ty *>( (&const_cast<char&>( reinterpret_cast<const volatile char&>(_Val))))); }
-
Und das ist der Grund, warum die Cast-Notation (und mit gewissen Einschränkungen auch die funktionale Notation) böse ist. Es ist nicht immer sofort offensichtlich, wie der Cast zu interpretieren ist (z.T. sogar dann, wenn der gesamte Quellcode bekannt ist 5.4./5)
-
zum Glück gibt es ja 5.2.10 11
An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators (and similarly for reinterpret_cast<T&&>(x)). The result refers to the same object as the source lvalue, but with a different type. The result is an lvalue for an lvalue reference type or an rvalue reference to function type and an xvalue for an rvalue reference to object type. No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.