Sempre pensei que uma assinatura como
int& val() {...}
indicaria ao chamador que uma referência a um valor int já existente é retornada. No entanto, se eu usar essa função e atribuí-la a uma int
variável (não a um int&
), ela será compilada. O resultado é, no entanto, uma cópia do valor real de retorno da função - conforme mostrado pela impressão dos endereços, como pode ser visto na sessão a seguir:
#include <iostream>
using namespace std;
int v = 8;
int& vref()
{
return v;
}
int main()
{
/*declared type of x does not match the return type! However, no warnings/messages about any implicit conversion are given here*/
int x = vref();
int& y = vref(); // correct type
// Now I declare pointers to x,y and v and display their addresses
int* ptr_x = &x;
int* ptr_y = &y;
int* ptr_v = &v;
cout << "Addr of x: " << ptr_x << endl;
cout << "Addr of y: " << ptr_y << endl;
cout << "Addr of v: " << ptr_v << endl;
}
Resultando y
e v
residindo no mesmo local de memória (o que eu esperava) - mas não x
. Então, eu me pergunto, o que está acontecendo nos bastidores ao atribuirint x = vref();
Com
você faz uma cópia do valor original e o armazena na variável única e distinta
x
.Por outro lado, com:
você obtém uma referência à
v
variável original. A variávely
pode ser vista como um alias dev
. Sempre que você usa,y
você está realmente usandov
.Como a
vref()
função retorna um alias dev
, a definição e inicialização dex
é realmente equivalente a:Ambos
x
ev
são do mesmo tipo, portanto nenhuma conversão de tipo é feita.Esta equivalência é obviamente a mesma para
y
a qual é equivalente a:Observe que o primeiro "problema", fazer uma cópia do valor retornado, é o motivo pelo qual não adianta retornar um valor constante.
Mesmo uma referência à constante (ou seja
int const&
, ) ainda pode ter seu valor copiado.A diferença é que se você modificar a cópia (como a variável
x
no seu exemplo), você modificará apenas a cópia em si, não o valor original.Então, por exemplo,
x++
aumentará o valor,x
mas não seráv
modificado. Masy++
aumentará o valor dev
.vref
retorna uma referência av
. As referências não podem ser recuperadas. A referência retornada devref
sempre se referirá av
. Usar a referência para inicializar outra referência faz com que essa outra referência se refira av
.Isto no entanto,
faz uma cópia
v
para inicializarx
.x
não é uma referência.x
ev
são dois inteiros distintos.Totalmente correto.
Não há contradição em
vref
retornar uma referência.