referências Quais são as diferenças entre uma variável de ponteiro e uma variável de referência em C++?




referências em c++ (24)

Eu sei que referências são açúcar sintático, 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:

  1. Um ponteiro pode ser reatribuído qualquer número de vezes, enquanto uma referência não pode ser reatribuída após a ligação.
  2. Ponteiros podem apontar para lugar nenhum ( NULL ), enquanto uma referência sempre se refere a um objeto.
  3. Você não pode pegar o endereço de uma referência como você pode com ponteiros.
  4. Não há "aritmética de referência" (mas você pode pegar o endereço de um objeto apontado por uma referência e fazer uma aritmética de ponteiro como em &obj + 5 ).

Para esclarecer um equívoco:

O padrão C ++ é muito cuidadoso para evitar ditar como um compilador pode implementar referências, mas todo compilador C ++ implementa referências como ponteiros. Isto é, uma declaração como:

int &ri = i;

se não for totalmente otimizado , aloca a mesma quantidade de armazenamento que um ponteiro e coloca o endereço de i nesse armazenamento.

Assim, um ponteiro e uma referência usam a mesma quantidade de memória.

Como uma regra geral,

  • Use referências em parâmetros de função e tipos de retorno para fornecer interfaces úteis e de auto-documentação.
  • Use ponteiros para implementar algoritmos e estruturas de dados.

Interessante ler:


Uma referência nunca pode ser NULL .


Uma referência a um ponteiro é possível em C ++, mas o inverso não é possível significa que um ponteiro para uma referência não é possível. Uma referência a um ponteiro fornece uma sintaxe mais limpa para modificar o ponteiro. Veja este exemplo:

#include<iostream>
using namespace std;

void swap(char * &str1, char * &str2)
{
  char *temp = str1;
  str1 = str2;
  str2 = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap(str1, str2);
  cout<<"str1 is "<<str1<<endl;
  cout<<"str2 is "<<str2<<endl;
  return 0;
}

E considere a versão C do programa acima. Em C você tem que usar ponteiro para ponteiro (múltipla indireta), e isso leva a confusão e o programa pode parecer complicado.

#include<stdio.h>
/* Swaps strings by swapping pointers */
void swap1(char **str1_ptr, char **str2_ptr)
{
  char *temp = *str1_ptr;
  *str1_ptr = *str2_ptr;
  *str2_ptr = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap1(&str1, &str2);
  printf("str1 is %s, str2 is %s", str1, str2);
  return 0;
}

Visite o seguinte para obter mais informações sobre a referência ao ponteiro:

Como eu disse, um ponteiro para uma referência não é possível. Experimente o seguinte programa:

#include <iostream>
using namespace std;

int main()
{
   int x = 10;
   int *ptr = &x;
   int &*ptr1 = ptr;
}

Correndo o risco de aumentar a confusão, eu quero inserir alguma entrada, tenho certeza que isso depende principalmente de como o compilador implementa referências, mas no caso do gcc, a ideia de que uma referência só pode apontar para uma variável na pilha não é realmente correto, tome isso por exemplo:

#include <iostream>
int main(int argc, char** argv) {
    // Create a string on the heap
    std::string *str_ptr = new std::string("THIS IS A STRING");
    // Dereference the string on the heap, and assign it to the reference
    std::string &str_ref = *str_ptr;
    // Not even a compiler warning! At least with gcc
    // Now lets try to print it's value!
    std::cout << str_ref << std::endl;
    // It works! Now lets print and compare actual memory addresses
    std::cout << str_ptr << " : " << &str_ref << std::endl;
    // Exactly the same, now remember to free the memory on the heap
    delete str_ptr;
}

O que gera isso:

THIS IS A STRING
0xbb2070 : 0xbb2070

Se você notar que os endereços de memória são exatamente os mesmos, significa que a referência está apontando com êxito para uma variável no heap! Agora, se você realmente quer ficar louco, isso também funciona:

int main(int argc, char** argv) {
    // In the actual new declaration let immediately de-reference and assign it to the reference
    std::string &str_ref = *(new std::string("THIS IS A STRING"));
    // Once again, it works! (at least in gcc)
    std::cout << str_ref;
    // Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
    delete &str_ref;
    /*And, it works, because we are taking the memory address that the reference is
    storing, and deleting it, which is all a pointer is doing, just we have to specify
    the address with '&' whereas a pointer does that implicitly, this is sort of like
    calling delete &(*str_ptr); (which also compiles and runs fine).*/
}

O que gera isso:

THIS IS A STRING

Portanto, uma referência é um ponteiro sob o capô, ambos estão apenas armazenando um endereço de memória, onde o endereço está apontando é irrelevante, o que você acha que aconteceria se eu chamasse std :: cout << str_ref; DEPOIS de chamar delete & str_ref? Bem, obviamente compila bem, mas causa uma falha de segmentação em tempo de execução porque não está mais apontando para uma variável válida, nós essencialmente temos uma referência quebrada que ainda existe (até que ela caia fora do escopo), mas é inútil.

Em outras palavras, uma referência nada mais é do que um ponteiro que abstrai a mecânica do ponteiro, tornando-a mais segura e fácil de usar (sem matemática acidental do ponteiro, sem misturar '.' E '->', etc.), supondo que você não tente nenhum absurdo como meus exemplos acima;)

Agora, independentemente de como um compilador trata referências, ele sempre terá algum tipo de ponteiro sob o capô, porque uma referência deve referir-se a uma variável específica em um endereço de memória específico para que funcione como esperado, não há como contornar isso o termo "referência").

A única regra importante que é importante lembrar com as referências é que elas devem ser definidas no momento da declaração (com a exceção de uma referência em um cabeçalho, nesse caso, ela deve ser definida no construtor, depois que o objeto contido nele for construiu é tarde demais para defini-lo).

Lembre-se, meus exemplos acima são apenas isso, exemplos demonstrando o que é uma referência, você nunca iria querer usar uma referência dessas maneiras! Para o uso adequado de uma referência, há muitas respostas aqui já que atingiram o prego na cabeça


Há uma diferença fundamental entre ponteiros e referências que eu não vi ninguém ter mencionado: referências permitem semântica de passagem por referência em argumentos de função. Ponteiros, embora não seja visível no início não: eles fornecem apenas semântica de passagem por valor. Isso foi muito bem descrito neste artigo .

Atenciosamente, & rzej


Na verdade, uma referência não é como um ponteiro.

Um compilador mantém "referências" a variáveis, associando um nome a um endereço de memória; Esse é o seu trabalho para traduzir qualquer nome de variável para um endereço de memória durante a compilação.

Quando você cria uma referência, você apenas informa ao compilador que você atribui outro nome à variável do ponteiro; é por isso que as referências não podem "apontar para nulo", porque uma variável não pode ser e não ser.

Ponteiros são variáveis; eles contêm o endereço de alguma outra variável ou podem ser nulos. O importante é que um ponteiro tenha um valor, enquanto uma referência tem apenas uma variável que está referenciando.

Agora alguma explicação do código real:

int a = 0;
int& b = a;

Aqui você não está criando outra variável que aponte para a ; você está apenas adicionando outro nome ao conteúdo da memória que contém o valor de a . Esta memória agora tem dois nomes, b , e pode ser endereçada usando qualquer nome.

void increment(int& n)
{
    n = n + 1;
}

int a;
increment(a);

Ao chamar uma função, o compilador geralmente gera espaços de memória para os argumentos a serem copiados. A assinatura da função define os espaços que devem ser criados e fornece o nome que deve ser usado para esses espaços. Declarar um parâmetro como referência apenas informa ao compilador para usar o espaço de memória da variável de entrada em vez de alocar um novo espaço de memória durante a chamada do método. Pode parecer estranho dizer que sua função manipulará diretamente uma variável declarada no escopo de chamada, mas lembre-se de que, ao executar o código compilado, não há mais escopo; há apenas memória simples, e seu código de função pode manipular quaisquer variáveis.

Agora pode haver alguns casos em que seu compilador pode não ser capaz de saber a referência ao compilar, como ao usar uma variável externa. Portanto, uma referência pode ou não ser implementada como um ponteiro no código subjacente. Mas nos exemplos que lhe dei, provavelmente não será implementado com um ponteiro.


O que é uma referência C ++ ( para programadores C )

Uma referência pode ser considerada como um ponteiro constante (não confundir com um ponteiro para um valor constante!) Com indireto automático, isto é, o compilador aplicará o operador * para você.

Todas as referências devem ser inicializadas com um valor não nulo ou a compilação falhará. Não é possível obter o endereço de uma referência - o operador de endereço retornará o endereço do valor referenciado - nem é possível fazer aritmética em referências.

Os programadores C podem não gostar de referências C ++, uma vez que deixará de ser óbvio quando ocorrer uma inflexão ou se um argumento for passado por valor ou por ponteiro sem olhar para as assinaturas de função.

Os programadores de C ++ podem não gostar de usar ponteiros, pois são considerados inseguros - embora as referências não sejam realmente mais seguras do que os ponteiros constantes, exceto nos casos mais triviais - não têm a conveniência da indireção automática e têm uma conotação semântica diferente.

Considere a seguinte declaração da FAQ do C ++ :

Mesmo que uma referência seja frequentemente implementada usando um endereço na linguagem de montagem subjacente, não pense em uma referência como um ponteiro de aparência engraçada para um objeto. Uma referência é o objeto. Não é um ponteiro para o objeto nem uma cópia do objeto. É o objeto.

Mas se uma referência realmente fosse o objeto, como poderia haver referências pendentes? Em idiomas não gerenciados, é impossível que as referências sejam mais "seguras" do que os ponteiros - geralmente não há uma forma de alias confiáveis ​​nos limites do escopo!

Por que eu considero as referências de C ++ úteis

Vindo de um segundo plano C, as referências em C ++ podem parecer um pouco tolas, mas ainda assim é necessário usá-las em vez de ponteiros: A indireção automática é conveniente, e as referências tornam-se especialmente úteis quando se lida com RAII - mas não por qualquer segurança percebida vantagem, mas sim porque eles fazem escrever código idiomático menos complicado.

O RAII é um dos conceitos centrais do C ++, mas interage de forma não trivial com a semântica de cópia. Passar objetos por referência evita esses problemas, pois não há cópias envolvidas. Se as referências não estivessem presentes no idioma, você teria que usar ponteiros, que são mais complicados de usar, violando assim o princípio do design de linguagem de que a solução de melhores práticas deveria ser mais fácil que as alternativas.


Talvez algumas metáforas ajudem; No contexto do seu espaço de tela da área de trabalho -

  • Uma referência requer que você especifique uma janela real.
  • Um ponteiro requer a localização de um pedaço de espaço na tela que você garante que ele conterá zero ou mais instâncias desse tipo de janela.

Eu sempre decido por this regra a partir das Diretrizes do C ++ Core:

Prefiro T * over T & quando "nenhum argumento" é uma opção válida


Uma referência não é outro nome dado a alguma memória. É um ponteiro imutável que é automaticamente desprezado no uso. Basicamente, resume-se a:

int& j = i;

Ele internamente se torna

int* const j = &i;

Não importa quanto espaço ele ocupe, já que você não pode realmente ver nenhum efeito colateral (sem executar código) de qualquer espaço que ocuparia.

Por outro lado, uma diferença importante entre referências e ponteiros é que os temporários atribuídos às referências constantes residem até que a referência const saia do escopo.

Por exemplo:

class scope_test
{
public:
    ~scope_test() { printf("scope_test done!\n"); }
};

...

{
    const scope_test &test= scope_test();
    printf("in scope\n");
}

vai imprimir:

in scope
scope_test done!

Esse é o mecanismo de linguagem que permite que o ScopeGuard funcione.


Uma referência é um alias para outra variável, enquanto um ponteiro contém o endereço de memória de uma variável. Referências são geralmente usadas como parâmetros de função para que o objeto passado não seja a cópia, mas o próprio objeto.

    void fun(int &a, int &b); // A common usage of references.
    int a = 0;
    int &b = a; // b is an alias for a. Not so common to use. 

Há uma diferença não-técnica muito importante entre ponteiros e referências: Um argumento passado para uma função por ponteiro é muito mais visível do que um argumento passado para uma função por referência não-const. Por exemplo:

void fn1(std::string s);
void fn2(const std::string& s);
void fn3(std::string& s);
void fn4(std::string* s);

void bar() {
    std::string x;
    fn1(x);  // Cannot modify x
    fn2(x);  // Cannot modify x (without const_cast)
    fn3(x);  // CAN modify x!
    fn4(&x); // Can modify x (but is obvious about it)
}

De volta ao C, uma chamada que parece fn(x)só pode ser passada por valor, então definitivamente não pode ser modificada x; para modificar um argumento, você precisaria passar um ponteiro fn(&x). Portanto, se um argumento não fosse precedido por um, &você sabia que ele não seria modificado. (O contrário, &meio modificado, não era verdade porque às vezes você teria que passar grandes estruturas somente leitura por constponteiro.)

Alguns argumentam que este é um recurso tão útil ao ler código, que os parâmetros de ponteiro devem sempre ser usados ​​para parâmetros modificáveis ​​em vez de não constreferências, mesmo que a função nunca espere a nullptr. Ou seja, essas pessoas argumentam que assinaturas de funções como fn3()acima não devem ser permitidas. As diretrizes de estilo C ++ do Google são um exemplo disso.


Diferença entre ponteiro e referência

Um ponteiro pode ser inicializado para 0 e uma referência não. De fato, uma referência também deve se referir a um objeto, mas um ponteiro pode ser o ponteiro nulo:

int* p = 0;

Mas não podemos ter int& p = 0;e tambémint& p=5 ; .

De fato, para fazê-lo corretamente, devemos ter declarado e definido um objeto no primeiro, então podemos fazer uma referência a esse objeto, então a implementação correta do código anterior será:

Int x = 0;
Int y = 5;
Int& p = x;
Int& p1 = y;

Outro ponto importante é que é possível fazer a declaração do ponteiro sem inicialização, porém isso não pode ser feito em caso de referência, que deve sempre fazer referência a variável ou objeto. No entanto, tal uso de um ponteiro é arriscado, então geralmente nós verificamos se o ponteiro está realmente apontando para algo ou não. No caso de uma referência, tal verificação é necessária, porque sabemos que a referência a um objeto durante a declaração é obrigatória.

Outra diferença é que o ponteiro pode apontar para outro objeto, mas a referência é sempre fazer referência ao mesmo objeto, vamos pegar este exemplo:

Int a = 6, b = 5;
Int& rf = a;

Cout << rf << endl; // The result we will get is 6, because rf is referencing to the value of a.

rf = b;
cout << a << endl; // The result will be 5 because the value of b now will be stored into the address of a so the former value of a will be erased

Outro ponto: quando temos um modelo como um modelo STL, esse tipo de modelo de classe sempre retornará uma referência, não um ponteiro, para facilitar a leitura ou atribuir um novo valor usando operator []:

Std ::vector<int>v(10); // Initialize a vector with 10 elements
V[5] = 5; // Writing the value 5 into the 6 element of our vector, so if the returned type of operator [] was a pointer and not a reference we should write this *v[5]=5, by making a reference we overwrite the element by using the assignment "="

Além do açúcar sintático, uma referência é um ponteiro const ( não ponteiro para um const ). Você deve estabelecer o que se refere quando declara a variável de referência e não pode alterá-la mais tarde.

Atualização: agora que penso um pouco mais, há uma diferença importante.

O alvo de um ponteiro const pode ser substituído tomando seu endereço e usando uma constelação.

O alvo de uma referência não pode ser substituído de forma alguma a partir do UB.

Isso deve permitir que o compilador faça mais otimização em uma referência.


Eu sinto que há ainda outro ponto que não foi abordado aqui.

Ao contrário dos ponteiros, as referências são sintaticamente equivalentes ao objeto ao qual se referem, ou seja, qualquer operação que possa ser aplicada a um objeto funciona para uma referência e com a mesma sintaxe exata (a exceção é, obviamente, a inicialização).

Embora isso possa parecer superficial, acredito que essa propriedade é crucial para vários recursos do C ++, por exemplo:

  • Templates . Como os parâmetros do modelo são tipificados com duck, as propriedades sintáticas de um tipo são tudo o que importa, portanto, o mesmo modelo pode ser usado com ambos Te T&.
    (ou std::reference_wrapper<T>que ainda depende de um elenco implícito para T&)
    Modelos que cobrem ambos T&e T&&são ainda mais comuns.

  • Lvalues . Considere a instrução str[0] = 'X';Sem referências, só funcionaria para strings-c ( char* str). Retornar o caractere por referência permite que as classes definidas pelo usuário tenham a mesma notação.

  • Copiar construtores . Sintaticamente, faz sentido passar objetos para copiar construtores e não ponteiros para objetos. Mas não há maneira de um construtor de cópia obter um objeto por valor - isso resultaria em uma chamada recursiva para o mesmo construtor de cópia. Isso deixa as referências como a única opção aqui.

  • Sobrecargas do operador . Com as referências, é possível introduzir indireção a uma chamada de operador - digamos, operator+(const T& a, const T& b)mantendo a mesma notação de infixação. Isso também funciona para funções sobrecarregadas regulares.

Esses pontos capacitam uma parte considerável do C ++ e da biblioteca padrão, de modo que essa é uma grande propriedade das referências.


Se você quer ser realmente pedante, há uma coisa que você pode fazer com uma referência que você não pode fazer com um ponteiro: estenda a vida útil de um objeto temporário. Em C ++, se você vincular uma referência const a um objeto temporário, a vida útil desse objeto se tornará a vida útil da referência.

std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

Neste exemplo, s3_copy copia o objeto temporário que é resultado da concatenação. Considerando s3_reference em essência torna-se o objeto temporário. É realmente uma referência a um objeto temporário que agora tem o mesmo tempo de vida da referência.

Se você tentar isso sem o const ele deve falhar na compilação. Você não pode vincular uma referência não-const a um objeto temporário, nem pode levar seu endereço para esse assunto.


Outro uso interessante de referências é fornecer um argumento padrão de um tipo definido pelo usuário:

class UDT
{
public:
   UDT() : val_d(33) {};
   UDT(int val) : val_d(val) {};
   virtual ~UDT() {};
private:
   int val_d;
};

class UDT_Derived : public UDT
{
public:
   UDT_Derived() : UDT() {};
   virtual ~UDT_Derived() {};
};

class Behavior
{
public:
   Behavior(
      const UDT &udt = UDT()
   )  {};
};

int main()
{
   Behavior b; // take default

   UDT u(88);
   Behavior c(u);

   UDT_Derived ud;
   Behavior d(ud);

   return 1;
}

O sabor padrão usa o aspecto 'vincular referência const a um temporário' de referências.


Ambas as referências e ponteiros podem ser usados ​​para alterar variáveis ​​locais de uma função dentro de outra função. Ambos também podem ser usados ​​para salvar a cópia de objetos grandes quando passados ​​como argumentos para funções ou retornados de funções, para obter ganho de eficiência. Apesar das semelhanças acima, existem as seguintes diferenças entre referências e ponteiros.

Referências são menos poderosas que ponteiros

1) Uma vez que uma referência é criada, ela não pode ser feita posteriormente para referenciar outro objeto; não pode ser recolocado. Isso geralmente é feito com ponteiros.

2) Referências não podem ser NULL. Os ponteiros costumam ser NULL para indicar que não estão apontando para nenhuma coisa válida.

3) Uma referência deve ser inicializada quando declarada. Não existe tal restrição com ponteiros

Devido às limitações acima, as referências em C ++ não podem ser usadas para implementar estruturas de dados como Lista vinculada, Árvore, etc. Em Java, as referências não têm restrições acima e podem ser usadas para implementar todas as estruturas de dados. Referências sendo mais poderosas em Java, é a principal razão pela qual o Java não precisa de ponteiros.

As referências são mais seguras e fáceis de usar:

1) Safer: Como as referências devem ser inicializadas, é improvável que existam referências selvagens como ponteiros silvestres. Ainda é possível ter referências que não se referem a um local válido

2) Mais fácil de usar: Referências não precisam de operador de referência para acessar o valor. Eles podem ser usados ​​como variáveis ​​normais. O operador '&' é necessário apenas no momento da declaração. Além disso, os membros de uma referência de objeto podem ser acessados ​​com o operador de ponto ('.'), Ao contrário dos ponteiros em que o operador de seta (->) é necessário para acessar os membros.

Juntamente com as razões acima, há poucos lugares como o argumento do construtor de cópia, em que o ponteiro não pode ser usado. A referência deve ser usada para passar o argumento no construtor de cópia. Similarmente, referências devem ser usadas para sobrecarregar alguns operadores como ++ .


Embora as referências e os ponteiros sejam usados ​​para acessar indiretamente outro valor, há duas diferenças importantes entre referências e ponteiros. A primeira é que uma referência sempre se refere a um objeto: é um erro definir uma referência sem inicializá-la. O comportamento da atribuição é a segunda diferença importante: a atribuição a uma referência altera o objeto ao qual a referência está vinculada; ele não liga novamente a referência a outro objeto. Uma vez inicializado, uma referência sempre se refere ao mesmo objeto subjacente.

Considere estes dois fragmentos de programa. No primeiro, atribuímos um ponteiro a outro:

int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
pi = pi2;    // pi now points to ival2

Após a atribuição, ival, o objeto endereçado por pi permanece inalterado. A atribuição altera o valor de pi, fazendo com que aponte para um objeto diferente. Agora considere um programa semelhante que atribua duas referências:

int &ri = ival, &ri2 = ival2;
ri = ri2;    // assigns ival2 to ival

Esta atribuição altera ival, o valor referenciado por ri, e não a própria referência. Após a atribuição, as duas referências ainda se referem a seus objetos originais, e o valor desses objetos é agora o mesmo também.


Outra diferença é que você pode ter ponteiros para um tipo void (e significa ponteiro para qualquer coisa), mas as referências a void são proibidas.

int a;
void * p = &a; // ok
void & p = a;  //  forbidden

Não posso dizer que estou realmente feliz com essa diferença em particular. Eu preferiria que fosse permitido com a referência de significado para qualquer coisa com um endereço e de outra forma o mesmo comportamento para referências. Isso permitiria definir alguns equivalentes das funções da biblioteca C, como o memcpy, usando referências.


Eu uso referências a menos que eu precise de um destes:

  • Os ponteiros nulos podem ser usados ​​como um valor sentinela, geralmente um modo barato de evitar a sobrecarga de funções ou o uso de um bool.

  • Você pode fazer aritmética em um ponteiro. Por exemplo,p += offset;


A diferença é que a variável de ponteiro não constante (que não deve ser confundida com um ponteiro para constante) pode ser alterada em algum momento durante a execução do programa, requer semântica de ponteiro (&, *), enquanto referências podem ser definidas na inicialização somente (é por isso que você pode defini-los apenas na lista de inicializadores de construtor, mas não de outra forma) e usar a semântica de acesso a valores comuns. Basicamente, referências foram introduzidas para permitir o suporte para sobrecarga de operadores, como eu li em algum livro muito antigo. Como alguém afirmou neste thread - ponteiro pode ser definido como 0 ou qualquer valor que você deseja. 0 (NULL, nullptr) significa que o ponteiro é inicializado com nada. É um erro excluir a referência do ponteiro nulo. Mas, na verdade, o ponteiro pode conter um valor que não aponta para algum local de memória correto.As referências, por sua vez, tentam não permitir que um usuário inicialize uma referência a algo que não pode ser referenciado devido ao fato de você sempre fornecer o valor correto do tipo para ele. Embora existam muitas maneiras de fazer com que a variável de referência seja inicializada em um local incorreto da memória - é melhor que você não consiga aprofundá-la nos detalhes. No nível da máquina, tanto o ponteiro quanto a referência funcionam uniformemente - por meio de ponteiros. Digamos que em referências essenciais o açúcar sintático. As referências de valor são diferentes disso - elas são naturalmente objetos de pilha / heap.Embora existam muitas maneiras de fazer com que a variável de referência seja inicializada em um local incorreto da memória - é melhor que você não consiga aprofundá-la nos detalhes. No nível da máquina, tanto o ponteiro quanto a referência funcionam uniformemente - por meio de ponteiros. Digamos que em referências essenciais o açúcar sintático. As referências de valor são diferentes disso - elas são naturalmente objetos de pilha / heap.Embora existam muitas maneiras de fazer com que a variável de referência seja inicializada em um local incorreto da memória - é melhor que você não consiga aprofundá-la nos detalhes. No nível da máquina, tanto o ponteiro quanto a referência funcionam uniformemente - por meio de ponteiros. Digamos que em referências essenciais o açúcar sintático. As referências de valor são diferentes disso - elas são naturalmente objetos de pilha / heap.


Este programa pode ajudar na compreensão da resposta da pergunta. Este é um programa simples de uma referência "j" e um ponteiro "ptr" apontando para a variável "x".

#include<iostream>

using namespace std;

int main()
{
int *ptr=0, x=9; // pointer and variable declaration
ptr=&x; // pointer to variable "x"
int & j=x; // reference declaration; reference to variable "x"

cout << "x=" << x << endl;

cout << "&x=" << &x << endl;

cout << "j=" << j << endl;

cout << "&j=" << &j << endl;

cout << "*ptr=" << *ptr << endl;

cout << "ptr=" << ptr << endl;

cout << "&ptr=" << &ptr << endl;
    getch();
}

Execute o programa e dê uma olhada na saída e você entenderá.

Além disso, poupe 10 minutos e assista a este vídeo: https://www.youtube.com/watch?v=rlJrrGV0iOg


Há uma diferença semântica que pode parecer esotérica se você não estiver familiarizado com o estudo de linguagens de computador de maneira abstrata ou acadêmica.

No nível mais alto, a ideia de referências é que elas são "aliases" transparentes. Seu computador pode usar um endereço para fazê-los funcionar, mas você não deve se preocupar com isso: você deve pensar neles como "apenas outro nome" para um objeto existente e a sintaxe reflete isso. Eles são mais rígidos do que os ponteiros, então seu compilador pode avisar com mais segurança quando você está prestes a criar uma referência pendente, do que quando você está prestes a criar um ponteiro pendente.

Além disso, existem algumas diferenças práticas entre ponteiros e referências. A sintaxe para usá-los é obviamente diferente, e você não pode "refazer" referências, ter referências a nada ou ter ponteiros para referências.





c++-faq