Temporäre können nicht an nicht konstante Referenzen gebunden werden. int (12) ist in diesem Fall vorübergehend.
Prasoon Saurav
@PrasoonSaurav Was meinst du mit temporären 12? Fehlende Konzepte hier (meinerseits :))
Aquarius_Girl
2
Beachten Sie, dass es keinen strengen technischen Grund für diese Einschränkung gibt. Es wäre genauso einfach zu implementieren gewesen, um veränderbare Verweise auf Provisorien zuzulassen . Das Verbot ist eine Entwurfsentscheidung von C ++, da eine solche Konstruktion ein schlechtes Design mit einem weitaus höheren Risiko eines versehentlichen Missbrauchs wäre als ein echtes Dienstprogramm. (Ich habe nur einmal einen erfundenen Bedarf für so etwas gefunden.)
Kerrek SB
@ KerrekSB die häufigste Notwendigkeit für eine Bindung ref zu rvalue Objekt ist wahrscheinlich(ostringstream() << "x=" << x).str()
neugierigguy
@curiousguy: Ja, das ist der Inhalt des Links, den ich gepostet habe.
Kerrek SB
Antworten:
130
In C ++ 03 3.10 / 1 heißt es: "Jeder Ausdruck ist entweder ein l-Wert oder ein r-Wert." Es ist wichtig, sich daran zu erinnern, dass Wertigkeit gegenüber Wertigkeit eine Eigenschaft von Ausdrücken ist, nicht von Objekten.
L-Werte benennen Objekte, die über einen einzelnen Ausdruck hinaus bestehen bleiben. Zum Beispiel obj, *ptr, ptr[index]und ++xsind alle lvalues.
R-Werte sind Provisorien, die am Ende des vollständigen Ausdrucks, in dem sie leben, verdunsten ("am Semikolon"). Beispielsweise,1729 , x + y, std::string("meow")und x++sind alle rvalues.
Die Adresse des Operators verlangt, dass sein "Operand ein Wert ist". Wenn wir die Adresse eines Ausdrucks nehmen könnten, wäre der Ausdruck ein l-Wert, andernfalls ein r-Wert.
" Wenn wir die Adresse eines Ausdrucks nehmen könnten, wäre der Ausdruck ein Wert, andernfalls ein Wert. " Wenn nur C ++ so einfach wäre! (aber die Nuance ist hier nicht wirklich relevant) "Rvalues are temporaries" temporär was? Objekte?
Neugieriger
1
@curiousguyRvalues sind temporäre Werte, die am Ende des vollständigen Ausdrucks, in dem sie leben, verschwinden. Um einfach zu beantworten, warum der Express int & = 12;ungültig ist, sagt der Standard, dass ein String-Literal ein l-Wert ist, andere Literale sind r-Werte.
BruceAdi
@curiousguy: Ja. R-Werte sind temporäre Objekte , aber nicht alle r-Werte sind temporäre Objekte. Einige sind nicht einmal Objekte.
Nawaz
" Zum Beispiel sind 1729, x + y, std :: string (" meow ") und x ++ alle r-Werte. " std::string("meow")Konstruiert jedoch ein Objekt vom Typ std::stringund liefert einen r-Wert, der dieses Objekt bezeichnet, 1729keine Nebenwirkungen hat und einen Wert liefert 1729 als Wert des Typs int.
Neugieriger
" L-Werte benennen Objekte, die über einen einzelnen Ausdruck hinaus bestehen. " Falsch, nehmen Sie:(const int&)1;
neugieriger Kerl
52
int&z =12;
Auf der rechten Seite intwird aus dem integralen Literal ein temporäres Objekt vom Typ erstellt , das temporäre Objekt 12kann jedoch nicht an eine nicht konstante Referenz gebunden werden. Daher der Fehler. Es ist dasselbe wie:
int&z =int(12);//still same error
Warum wird eine temporäre erstellt? Da sich eine Referenz auf ein Objekt im Speicher beziehen muss und ein Objekt vorhanden sein muss, muss es zuerst erstellt werden. Da das Objekt unbenannt ist, handelt es sich um ein temporäres Objekt. Es hat keinen Namen. Aus dieser Erklärung wurde ziemlich klar, warum der zweite Fall in Ordnung ist.
Ein temporäres Objekt kann an eine const-Referenz gebunden werden. Dies bedeutet, dass Sie Folgendes tun können:
constint&z =12;//ok
C ++ 11 und Rvalue Referenz:
Der Vollständigkeit halber möchte ich hinzufügen, dass C ++ 11 eine rvalue-Referenz eingeführt hat, die an ein temporäres Objekt gebunden werden kann. In C ++ 11 können Sie also Folgendes schreiben:
int&& z =12;//C+11 only
Beachten Sie, dass es &&intead von gibt &. Beachten Sie auch, dass dies constnicht mehr benötigt wird, obwohl das Objekt, an das zgebunden wird, ein temporäres Objekt ist, das aus einem Integral-Literal erstellt wurde 12.
Da C ++ 11 rvalue-reference eingeführt hat , int&wird es nun als lvalue-reference bezeichnet .
12ist eine Konstante zur Kompilierungszeit, die im Gegensatz zu den Daten, auf die verwiesen wird, nicht geändert werden kann int&. Was Sie tun können , ist
@curiousguy, sei konsequent, du hast gesagt "Du musst verstehen, dass dies C ++ - Regeln sind. Sie existieren und brauchen keine Begründung" (ganz zu schweigen von der ersten Ausgabe). Wie soll ich Ihre Beschwerde interpretieren, nicht zu geben, was Ihrer Meinung nach nicht benötigt wird?
Michael Krelin - Hacker
2
@ MichaelKrelin-hacker: Technisch gesehen kann man (nie) keinen Verweis auf einen Wert (oder eine Kompilierungszeitkonstante) binden, der Standard ist ziemlich explizit, was tatsächlich passiert: Andernfalls wird ein Temporär vom Typ "cv1 T1" erstellt und Initialisiert aus dem Initialisierungsausdruck unter Verwendung der Regeln für eine Nichtreferenzkopie-Initialisierung (8.5). Die Referenz wird dann an das Temporäre gebunden. Das heißt, die Syntax ist zulässig, aber die Semantik besteht nicht darin, eine Referenz an die Konstante zu binden, sondern sie an das Temporäre zu binden, das implizit erstellt wird.
David Rodríguez - Dribeas
1
@curiousguy: Die Regeln der Sprache sind Teil des Designs, und meistens gibt es Rechtfertigungen dafür, warum die Sprache so gestaltet wurde. In diesem speziellen Fall, wie in C, dürfen Sie weder die Adresse eines Wertes übernehmen (es hat keinen), noch können Sie eine Referenz binden. Betrachten Sie nun eine Funktion void f( vector<int> const & ), die idiomatisch ist, um einen Vektor zu übergeben, der nicht geändert werden soll. Das Problem ist jetzt, dass f( vector<int>(5) )dies falsch wäre und der Benutzer eine andere Überlastung bereitstellen müsste, void f( vector<int> v ) { f(v); }was trivial ist.
David Rodríguez - Dribeas
1
... nun, da dies für die Benutzer der Sprache schmerzhaft wäre, haben die Designer entschieden, dass der Compiler die entsprechende Operation für Sie ausführen würde. Beim Aufruf erstellt f( vector<int>(5) )der Compiler eine temporäre und bindet dann den Verweis auf diese temporäre und ähnliche wenn es eine implizite Konvertierung von 5direkt gab. Dies ermöglicht dem Compiler, eine einzelne Signatur für die Funktion zu generieren, und ermöglicht eine Einzelbenutzerimplementierung der Funktion. Von da an wird ein ähnliches Verhalten für den Rest der Verwendung konstanter Referenzen zur Konsistenz definiert.
David Rodríguez - Dribeas
1
@ MichaelKrelin-Hacker: Verweise sind Aliase auf Objekte, und ein Wert ist kein Objekt. Abhängig vom Kontext können Referenzen nur ein Alias sein. Der Compiler entfernt die Referenz und verwendet den Bezeichner, um zu bedeuten, was auch immer das ursprüngliche Objekt bedeutet ( T const & r = *ptr;jede spätere Verwendung rin der Funktion kann durch ersetzt werden *ptrund rmuss zur Laufzeit nicht vorhanden sein). oder es muss möglicherweise implementiert werden, indem die Adresse des Objekts beibehalten wird, das es als Aliase verwendet (speichern Sie eine Referenz als Mitglied eines Objekts) - das als automatisch referenzierter Zeiger implementiert ist.
David Rodríguez - Dribeas
4
Non-Const- und Const-Referenzbindung folgen unterschiedlichen Regeln
Dies sind die Regeln der C ++ - Sprache:
ein Ausdruck bestehend aus einer Literalzahl (12 Literalzahl ) besteht, ist ein "rWert".
Es ist nicht zulässig, eine nicht konstante Referenz mit einem r-Wert zu erstellen: int &ri = 12; ist schlecht geformt
Es ist zulässig, eine const-Referenz mit einem r-Wert zu erstellen. In diesem Fall wird vom Compiler ein unbenanntes Objekt erstellt. Dieses Objekt bleibt bestehen, solange die Referenz selbst vorhanden ist.
Sie müssen verstehen, dass dies C ++ - Regeln sind. Sie sind es einfach.
Es ist einfach, eine andere Sprache zu erfinden, beispielsweise C ++ ', mit leicht unterschiedlichen Regeln. In C ++ 'wäre es zulässig, eine nicht konstante Referenz mit einem r-Wert zu erstellen. Hier ist nichts inkonsistent oder unmöglich.
Aber es würde einen riskanten Code ermöglichen, bei dem der Programmierer möglicherweise nicht das bekommt, was er beabsichtigt hat, und C ++ - Designer haben zu Recht beschlossen, dieses Risiko zu vermeiden.
Verweise sind "versteckte Zeiger" (nicht null) auf Dinge, die sich ändern können (lWerte). Sie können sie nicht als Konstante definieren. Es sollte eine "variable" Sache sein.
BEARBEITEN::
ich denke an
int&x = y;
als fast gleichwertig mit
int* __px =&y;#define x (*__px)
wo __pxist ein neuer Name, und das #define xfunktioniert nur innerhalb des Blocks, der die xReferenzdeklaration enthält.
(ostringstream() << "x=" << x).str()
Antworten:
In C ++ 03 3.10 / 1 heißt es: "Jeder Ausdruck ist entweder ein l-Wert oder ein r-Wert." Es ist wichtig, sich daran zu erinnern, dass Wertigkeit gegenüber Wertigkeit eine Eigenschaft von Ausdrücken ist, nicht von Objekten.
L-Werte benennen Objekte, die über einen einzelnen Ausdruck hinaus bestehen bleiben. Zum Beispiel
obj
,*ptr
,ptr[index]
und++x
sind alle lvalues.R-Werte sind Provisorien, die am Ende des vollständigen Ausdrucks, in dem sie leben, verdunsten ("am Semikolon"). Beispielsweise,
1729
,x + y
,std::string("meow")
undx++
sind alle rvalues.Die Adresse des Operators verlangt, dass sein "Operand ein Wert ist". Wenn wir die Adresse eines Ausdrucks nehmen könnten, wäre der Ausdruck ein l-Wert, andernfalls ein r-Wert.
quelle
int & = 12;
ungültig ist, sagt der Standard, dass ein String-Literal ein l-Wert ist, andere Literale sind r-Werte.std::string("meow")
Konstruiert jedoch ein Objekt vom Typstd::string
und liefert einen r-Wert, der dieses Objekt bezeichnet,1729
keine Nebenwirkungen hat und einen Wert liefert 1729 als Wert des Typsint
.(const int&)1;
Auf der rechten Seite
int
wird aus dem integralen Literal ein temporäres Objekt vom Typ erstellt , das temporäre Objekt12
kann jedoch nicht an eine nicht konstante Referenz gebunden werden. Daher der Fehler. Es ist dasselbe wie:Warum wird eine temporäre erstellt? Da sich eine Referenz auf ein Objekt im Speicher beziehen muss und ein Objekt vorhanden sein muss, muss es zuerst erstellt werden. Da das Objekt unbenannt ist, handelt es sich um ein temporäres Objekt. Es hat keinen Namen. Aus dieser Erklärung wurde ziemlich klar, warum der zweite Fall in Ordnung ist.
Ein temporäres Objekt kann an eine const-Referenz gebunden werden. Dies bedeutet, dass Sie Folgendes tun können:
C ++ 11 und Rvalue Referenz:
Der Vollständigkeit halber möchte ich hinzufügen, dass C ++ 11 eine rvalue-Referenz eingeführt hat, die an ein temporäres Objekt gebunden werden kann. In C ++ 11 können Sie also Folgendes schreiben:
Beachten Sie, dass es
&&
intead von gibt&
. Beachten Sie auch, dass diesconst
nicht mehr benötigt wird, obwohl das Objekt, an dasz
gebunden wird, ein temporäres Objekt ist, das aus einem Integral-Literal erstellt wurde12
.Da C ++ 11 rvalue-reference eingeführt hat ,
int&
wird es nun als lvalue-reference bezeichnet .quelle
12
ist eine Konstante zur Kompilierungszeit, die im Gegensatz zu den Daten, auf die verwiesen wird, nicht geändert werden kannint&
. Was Sie tun können , istquelle
void f( vector<int> const & )
, die idiomatisch ist, um einen Vektor zu übergeben, der nicht geändert werden soll. Das Problem ist jetzt, dassf( vector<int>(5) )
dies falsch wäre und der Benutzer eine andere Überlastung bereitstellen müsste,void f( vector<int> v ) { f(v); }
was trivial ist.f( vector<int>(5) )
der Compiler eine temporäre und bindet dann den Verweis auf diese temporäre und ähnliche wenn es eine implizite Konvertierung von5
direkt gab. Dies ermöglicht dem Compiler, eine einzelne Signatur für die Funktion zu generieren, und ermöglicht eine Einzelbenutzerimplementierung der Funktion. Von da an wird ein ähnliches Verhalten für den Rest der Verwendung konstanter Referenzen zur Konsistenz definiert.T const & r = *ptr;
jede spätere Verwendungr
in der Funktion kann durch ersetzt werden*ptr
undr
muss zur Laufzeit nicht vorhanden sein). oder es muss möglicherweise implementiert werden, indem die Adresse des Objekts beibehalten wird, das es als Aliase verwendet (speichern Sie eine Referenz als Mitglied eines Objekts) - das als automatisch referenzierter Zeiger implementiert ist.Non-Const- und Const-Referenzbindung folgen unterschiedlichen Regeln
Dies sind die Regeln der C ++ - Sprache:
12
Literalzahl ) besteht, ist ein "rWert".int &ri = 12;
ist schlecht geformtSie müssen verstehen, dass dies C ++ - Regeln sind. Sie sind es einfach.
Es ist einfach, eine andere Sprache zu erfinden, beispielsweise C ++ ', mit leicht unterschiedlichen Regeln. In C ++ 'wäre es zulässig, eine nicht konstante Referenz mit einem r-Wert zu erstellen. Hier ist nichts inkonsistent oder unmöglich.
Aber es würde einen riskanten Code ermöglichen, bei dem der Programmierer möglicherweise nicht das bekommt, was er beabsichtigt hat, und C ++ - Designer haben zu Recht beschlossen, dieses Risiko zu vermeiden.
quelle
Verweise sind "versteckte Zeiger" (nicht null) auf Dinge, die sich ändern können (lWerte). Sie können sie nicht als Konstante definieren. Es sollte eine "variable" Sache sein.
BEARBEITEN::
ich denke an
als fast gleichwertig mit
wo
__px
ist ein neuer Name, und das#define x
funktioniert nur innerhalb des Blocks, der diex
Referenzdeklaration enthält.quelle
const
:)const