Eu sei que as referências são açúcar sintáctico, então o código é mais fácil de ler e escrever.
Mas quais são as diferenças?
Resumo das respostas e links abaixo:
NULL
), enquanto que uma referência sempre se refere a um objeto.&obj + 5
).Para esclarecer um equívoco:
O padrão C++ é muito cuidadoso para evitar ditar como um compilador pode implementar referências, mas cada compilador C++ implementa referências como apontadores. Ou seja, uma declaração como:
int &ri = i;
if it's não otimizado inteiramente, aloca a mesma quantidade de armazenamento como um ponteiro, e coloca o endereço de
i
para aquele armazenamento.
Então, um ponteiro e uma referência usam ambos a mesma quantidade de memória.
Como regra geral,
Uma leitura interessante:
Um ponteiro pode ser reatribuído:
int x = 5;
int y = 6;
int *p;
p = &x;
p = &y;
*p = 10;
assert(x == 5);
assert(y == 10);
Uma referência não pode, e deve ser atribuída na inicialização:
int x = 5;
int y = 6;
int &r = x;
Um ponteiro tem seu próprio endereço de memória e tamanho na pilha (4 bytes em x86), enquanto uma referência compartilha o mesmo endereço de memória (com a variável original), mas também ocupa algum espaço na pilha. Como uma referência tem o mesmo endereço que a própria variável original, é seguro pensar em uma referência como outro nome para a mesma variável. Nota: O que um ponteiro aponta para pode estar na pilha ou na pilha. Idem a uma referência. Minha afirmação nesta declaração não é que um ponteiro deve apontar para a pilha. Um ponteiro é apenas uma variável que contém um endereço de memória. Esta variável está na pilha. Como uma referência tem o seu próprio espaço na pilha, e como o endereço é o mesmo que a variável a que se refere. Mais sobre stack vs heap. Isto implica que há um endereço real de uma referência que o compilador não lhe dirá.
int x = 0;
int &r = x;
int *p = &x;
int *p2 = &r;
assert(p == p2);
Você pode ter apontadores para apontadores para apontadores que oferecem níveis extra de indireção. Enquanto as referências oferecem apenas um nível de indireção.
int x = 0;
int y = 0;
int *p = &x;
int *q = &y;
int **pp = &p;
pp = &q;//*pp = q
**pp = 4;
assert(y == 4);
assert(x == 0);
O ponteiro pode ser atribuído diretamente a nullptr
, enquanto a referência não pode. Se você se esforçar o suficiente, e você sabe como, você pode fazer o endereço de uma referência nullptr
. Da mesma forma, se você se esforçar o suficiente, você pode ter uma referência a um ponteiro, e então essa referência pode conter nullptr
.
int *p = nullptr;
int &r = nullptr; <--- erro de compilação
int &r = *p; <--- provavelmente sem erro de compilação, especialmente se o nullptr estiver escondido atrás de uma chamada de função, mas refere-se a uma int inexistente no endereço 0
Os ponteiros podem iterar sobre um array, você pode usar ++
para ir para o próximo item que um ponteiro está apontando, e + 4
para ir para o 5º elemento. Não importa o tamanho do objeto para o qual o ponteiro está apontando.
Um ponteiro precisa ser desreferenciado com *' para acessar a localização da memória para a qual aponta, enquanto uma referência pode ser utilizada diretamente. Um ponteiro para uma classe/estrutura utiliza
->para acessar seus membros, enquanto uma referência utiliza
.``.
Um ponteiro é uma variável que contém um endereço de memória. Independentemente de como uma referência é implementada, uma referência tem o mesmo endereço de memória que o item que ela referencia.
As referências não podem ser enfiadas em um array, enquanto os apontadores podem ser (Mencionado pelo usuário @litb)
As referências constantes podem ser vinculadas aos temporários. Os ponteiros não podem (não sem alguma indireção):
const int &x = int(12); //legal C++
int *y = &int(12); //illegal para desreferenciar um temporário.
Isto torna o `const&' mais seguro para utilização em listas de argumentos e assim por diante.
Além do açúcar sintáctico, uma referência é um ponteiro const' (*não* ponteiro para um
const'). Deve-se estabelecer a que se refere quando se declara a variável de referência, e não se pode modificá-la posteriormente.
Atualização: agora que penso um pouco mais sobre isso, há uma diferença importante.
O alvo de um ponteiro constante pode ser substituído tomando o seu endereço e usando um elenco constante.
O alvo de uma referência não pode ser substituído de forma alguma sem UB.
Isto deve permitir que o compilador faça mais otimização em uma referência.