Ist der folgende Code zulässig (nach C ++ 11 und / oder C ++ 14 Standard (en))?
%Vor%a
in foo
mutieren, ohne dass es UB wird? Es kompiliert auf clang 3.5, nicht auf gcc 4.9. GCC-Fehler:
%Vor% FYI, eine benutzerdefinierte Cast, die weniger behaart ist als die vorherige, und die auf C ++ 11 sowohl für GCC als auch für Clang funktioniert, wäre die folgende Funktion lvalue
:
Update: Der Code ist in C ++ 11 schlecht formatiert. Die Antwort unten ist für C ++ 14. Siehe Hinweis am Ende dieser Antwort.
Ich glaube, dass dieser Code sowohl wohlgeformt als auch gut definiert ist. Hier ist der Grund.
Das Ergebnis von std::move
ist ein xvalue [1], was eine Art von glvalue ist; und das Konvertieren eines gl-Wertes in eine l-Wert-Referenz mit reinterpret_cast
scheint durch den Wortlaut des Standards erlaubt zu sein:
Ein glvalue-Ausdruck vom Typ
T1
kann in den Typ "Verweis aufT2
" umgewandelt werden, wenn ein Ausdruck vom Typ "pointer" verwendet wird toT1
"kann mit einemT2
explizit in den Typ" pointer toreinterpret_cast
"konvertiert werden. Das Ergebnis bezieht sich zu dem gleichen Objekt wie der Quell-gl-Wert, aber mit dem angegebenen Typ. [Anmerkung: Das ist für lvalues eine Referenz Castreinterpret_cast<T&>(x)
hat den gleichen Effekt wie die Conversion*reinterpret_cast<T*>(&x)
mit die integrierten Operatoren&
und*
(und ähnlich fürreinterpret_cast<T&&>(x)
). - Endnote] Keine temporäre wird erstellt, es wird keine Kopie erstellt und Konstruktoren (12.1) oder Konvertierungsfunktionen (12.3) werden nicht aufgerufen.73
Da "pointer to int
" in "pointer to int
" konvertiert werden kann, ist auch dieses reinterpret_cast
erlaubt. Der Standard sagt nichts darüber aus, ob der Zieltyp eine lvalue-Referenz oder eine rvalue-Referenz sein muss.
Das Ergebnis der Umwandlung ist durch den obigen Absatz klar definiert: Es bezieht sich auf das gleiche Objekt wie der Quell-glvalue --- also ein temporäres int
-Objekt mit dem Wert 5
. ([dcl.init.ref] gibt an, dass ein temporäres Objekt erstellt wird, wenn ein prvalue an eine Referenz gebunden ist.)
Der Zugriff auf den Wert über int&
verletzt auch keine Aliasregeln, da das ursprüngliche Objekt auch vom Typ int
war. Tatsächlich glaube ich, dass es sogar gut definiert wäre, das Temporäre durch den so erhaltenen Wert zu modifizieren.
Hinweis: In der C ++ 11-Formulierung steht "lvalue expression", nicht "glvalue expression". Die Formulierung mit "glvalue-Ausdruck" stammt aus N3936, dem letzten Arbeitsentwurf für C ++ 14. Ich bin kein Experte dafür, wie der Standardisierungsprozess funktioniert, aber ich glaube, das bedeutet, dass die Änderung von "lvalue" zu "glvalue" bereits vom Komitee abgestimmt wurde und wenn ISO den C ++ 14-Standard veröffentlicht, wird es gehen ziemlich ähnlich zu dem sein, was es oben sagt.
[1] Außer in dem seltenen Fall, in dem das Argument eine Funktion ist; In diesem Fall ist das Ergebnis ein Lvalue, da es keine Funktion rvalues gibt.
Das Problem wird aktiviert, wenn reinterpret_cast xvalues in lvalues konvertieren darf. Im Gegensatz zu dem, was andere einfügen, erwähnt der relevante Absatz (5.2.10.11) nur lvalues:
Ein lvalue-Ausdruck vom Typ T1 kann in den Typ "reference to" umgewandelt werden T2 "wenn ein Ausdruck vom Typ "Zeiger auf T1" kann explizit in den Typ konvertiert werden "Pointer to T2" mit einem reinterpret_cast ..
Es gibt einen Vorschlag von Michael Wong, den Wortlaut in glvalue zu ändern, aber es scheint eine Wand zu treffen:
Ich nehme an, dass dies bedeutet, dass die Konvertierung ab sofort nicht legal ist, da sie nur die Konvertierung von lvalues erlaubt.
Der relevante Abschnitt in der Norm ist 5.2.10 [expr.reinterpret.cast]. Es gibt zwei relevante Absätze:
Erstens gibt es Absatz 1, der endet in:
Keine andere Konvertierung kann explizit mit reinterpret_cast durchgeführt werden.
... und Absatz 11, da keiner der anderen gilt:
Ein glvalue-Ausdruck vom Typ
T1
kann in den Typ "Verweis aufT2
" umgewandelt werden, wenn ein Ausdruck vom Typ "Zeiger aufT1
" explizit in den Typ "Zeiger aufT2
" konvertiert werden kann mit einemreinterpret_cast
. Das Ergebnis bezieht sich auf das gleiche Objekt wie der Quell-gl-Wert, aber mit dem angegebenen Typ. [Anmerkung: Das heißt, für lvalues hat eine Referenzbesetzungreinterpret_cast<T&>(x)
den gleichen Effekt wie die Konversion*reinterpret_cast<T*>(&x)
mit den integrierten Operatoren&
und*
(und ähnlich fürreinterpret_cast<T&&>(x))
. - Endnote) Kein Temporär wird erstellt, es wird keine Kopie erstellt und Konstruktoren (12.1) oder Konvertierungsfunktionen (12.3) werden nicht aufgerufen.
Alle anderen Klauseln gelten nicht für Objekte, sondern nur für Zeiger, Zeiger auf Funktionen usw. Da ein rvalue kein glvalue ist, ist der Code illegal.
Tags und Links c++ c++11 language-lawyer reinterpret-cast c++14