Non possiamo scrivere int& ref = 40
perché abbiamo bisogno di lvalue
sul lato destro. Ma possiamo scrivere const int& ref = 40
. Perché è possibile? 40 è rvalue
invece lvalue
Const reference e lvalue
So che questa è un'eccezione, ma perché?
Non possiamo scrivere int& ref = 40
perché abbiamo bisogno di lvalue
sul lato destro. Ma possiamo scrivere const int& ref = 40
. Perché è possibile? 40 è rvalue
invece lvalue
Const reference e lvalue
So che questa è un'eccezione, ma perché?
Come Stroustrup dice:
L'inizializzatore di un const T & Non occorre essere un lvalue o anche di tipo T. In tal caso:
[1] Primo, conversione di tipo implicita T viene applicato se necessario.
[2] Quindi, il valore risultante viene posto in una variabile temporanea di tipo T.
[3] Infine, questa variabile temporanea viene utilizzato come valore del inizializzatore.
Quindi, quando si digita const int& ref = 40
, la variabile temporanea int viene creata dietro le quinte e il riferimento è associato a questa variabile temporanea.
C'è una regola nella lingua che consente di associare un riferimento di constval a un valore. La ragione principale di questa regola è che, se non era presente, allora si dovrebbe fornire diversi sovraccarichi di funzioni per essere in grado di utilizzare provvisori come argomenti:
class T; // defined somewhere
T f();
void g(T const &x);
Con questa regola nel luogo che si può fare g(f())
, senza di essa, per essere in grado di farlo si dovrà creare una diversa g
overload che accetta un rvalue (e questo è da un tempo in cui rvalue riferimenti non erano nemmeno nella lingua!)
Non sono ancora sicuro del motivo per cui [la durata è estesa] (http://stackoverflow.com/q/20546981/596781), però :-( –
@KerrekSB: Immagino che la ragione originale fosse che in questo modo potevi scrivere 'T const & _ = ...;' o 'T const _ = ...; 'indifferentemente ed entrambi funzionerebbero, il primo è più efficiente quando l'espressione produce un riferimento (nessuna copia). E 'davvero sfortunato, però, perché lascia entrare molti ma. –
@KerrekSB: Pensavo di averlo indirizzato nella domanda collegata. Questo è un effetto collaterale di consentire l'associazione nel contesto generale (non solo negli argomenti della funzione) e non volendo che causi un comportamento indefinito ad ogni uso. Senza l'estensione della durata: 'T const & x = f(); 'seguito da * qualsiasi * odr-uso di' x' sarebbe un comportamento indefinito, sollevando la questione del perché permetterlo in primo luogo? Quindi o fornite consistenza (riferimenti di riferimento in * qualsiasi * contesto) con estensione a vita, oppure accettate incoerenze e non vi è alcuna necessità di estensione a vita. Il linguaggio ha fatto il primo. –
perché è possibile?
40 è un letterale qui. I riferimenti costanti possono essere inizializzati con letterali e temporanei per prolungare la loro vita. Questo può essere fatto in questo modo da un compilatore:
int const& ans = 40;
// transformed:
int __internal_unique_name = 40;
int const& ans = __internal_unique_name;
Un'altra situazione è quando si dispone di una funzione, ad esempio:
void f(std::string const& s);
e si desidera chiamare con
f("something");
Questo la variabile temporanea può essere solo associata al riferimento const.
Questo è anche il caso con riferimenti non const ... –
@ DavidRodríguez-dribeas non è la seconda situazione fornita – 4pie0
Questo è esattamente ciò che il compilatore farà per te, esegue il mapping della chiamata a: 'std :: string __tmp (" qualcosa"); f (__ tmp); '. Cioè * perché è possibile * non è un motivo per consentire questo per i riferimenti 'const' (* alone *), come dimostrato dal fatto che sia Solaris CC che VS hanno supportato i riferimenti non-const vincolanti ai provvisori facendo esattamente lo stesso cosa. –
È possibile associare un valore rval a un riferimento const. Il linguaggio garantisce che l'oggetto associato sopravvive fino a quando non termina lo scopo del riferimento e anche in modo statico chiama il distruttore corretto. Questo è ad es. utilizzato in un'implementazione ScopeGuard (http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758?pgno=2) per avere un comportamento simile a un distruttore virtuale senza pagare una chiamata al metodo virtuale.
Il compilatore non ha una scelta che contenga. Le regole del linguaggio dettano le vite. –
Definitivamente un dupe. –