Ponteiro vs Referência
Pergunta
O que seria melhor prática ao dar uma função a variável original para trabalhar com:
unsigned long x = 4;
void func1(unsigned long& val) {
val = 5;
}
func1(x);
ou
void func2(unsigned long* val) {
*val = 5;
}
func2(&x);
IOW: Existe alguma razão para escolher um sobre o outro
?Solução
A minha regra de ouro é:
Use ponteiros se você quer fazer aritmética de ponteiro com eles (por exemplo, incrementando o endereço do ponteiro para percorrer um array) ou se você tiver que passar um NULL-pointer.
Use referências contrário.
Outras dicas
Eu realmente acho que você vai beneficiar de estabelecer a seguinte função chamar diretrizes de codificação:
-
Como em todos os outros lugares, sempre
const
-correta.- Nota:. Isto significa, entre outras coisas, que apenas out-valores (ver item 3) e os valores passados ??por valor (vide item 4) pode faltar o especificador
const
- Nota:. Isto significa, entre outras coisas, que apenas out-valores (ver item 3) e os valores passados ??por valor (vide item 4) pode faltar o especificador
-
Apenas passar um valor de ponteiro se o valor 0 / NULL é uma entrada válida no contexto atual.
-
Razão 1:. Como um chamador , você vê que o que você passar em deve ser em um estado utilizável
-
Razão 2: Como chamado , você sabe que tudo o que vem em é em um estado utilizável. Assim, não NULL-cheque ou erro de manipulação precisa de ser feito para esse valor.
-
Razão 3: Rationales 1 e 2 serão compilador Forçados . Sempre detectar erros em tempo de compilação, se puder.
-
-
Se um argumento de função é um valor, então passá-lo por referência.
- Justificativa: Nós não queremos quebrar o item 2 ...
-
Escolha "passar por valor" sobre "passar por referência const" somente se o valor é um POD ( Plain datastructure velho ) ou pequeno o suficiente (memória-wise) ou de outras formas bastante barato (time-wise) para copiar.
- Justificativa:. Evitar cópias desnecessárias
- Nota:. pequeno o suficiente e o suficiente barato não são mensuráveis ??absolutos
Esta última análise, acaba por ser subjetiva. A discussão até agora é útil, mas eu não acho que há uma resposta correta ou decisiva para isso. Muita coisa vai depender de diretrizes de estilo e suas necessidades no momento.
Embora existam algumas capacidades diferentes (ou não algo pode ser NULL) com um ponteiro, a maior diferença prática para um parâmetro de saída é puramente sintaxe. Guia de Estilo do Google C ++ ( https://google.github.io/styleguide/cppguide.html# Reference_Arguments ), por exemplo, mandatos somente ponteiros para parâmetros de saída, e permite que apenas as referências que são const. O raciocínio é uma das legibilidade: algo com sintaxe valor não deve ter ponteiro significado semântico. Não estou sugerindo que este é necessariamente certo ou errado, mas acho que o ponto aqui é que é uma questão de estilo, não de correção.
Você deve passar um ponteiro se você estiver indo para modificar o valor da variável. Mesmo que tecnicamente passando uma referência ou um ponteiro são o mesmo, passando um ponteiro em seu caso de uso é mais legível como ele "anuncia" o fato de que o valor será alterado pela função.
Se você tem um parâmetro que pode ser necessário para indicar a ausência de um valor, é prática comum para fazer o parâmetro um valor de ponteiro e passar NULL.
A melhor solução na maioria dos casos (a partir de uma perspectiva de segurança) é a utilização de boost :: opcional . Isso permite que você passar em valores opcionais por referência e também como um valor de retorno.
// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
if (optional_str)
{
cout << *optional_str << std::endl;
}
else
{
cout << "(no string)" << std::endl;
}
}
// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
if (return_nothing)
{
return boost::optional<int>();
}
return boost::optional<int>(42);
}
Use uma referência quando você pode, usar um ponteiro quando você tem que. De C ++ FAQ: "Quando devo usar referências, e quando devo usar ponteiros"
Ponteiros
- Um ponteiro é uma variável que contém um endereço de memória.
- Uma declaração de ponteiro é constituído por um tipo de base, um *, e o nome da variável.
- Um ponteiro pode apontar para qualquer número de variáveis ??no tempo de vida
-
Um ponteiro que não aponta para uma localização de memória válido atualmente é dado o nulo valor (que é zero)
BaseType* ptrBaseType; BaseType objBaseType; ptrBaseType = &objBaseType;
-
O & é um operador unário que retorna o endereço de memória de seu operando.
-
operador Dereferencing (*) é utilizado para o acesso o valor armazenado na variável que aponta para o ponteiro.
int nVar = 7; int* ptrVar = &nVar; int nVar2 = *ptrVar;
Referência
-
A referência (&) é como um nome alternativo para uma variável existente.
-
A referência (&) é semelhante a um ponteiro constante que é automaticamente desreferenciado.
-
É normalmente usado para listas de argumentos de função e valores de retorno de função.
-
Uma referência deve ser inicializado quando ele é criado.
-
Uma vez que uma referência é inicializado para um objecto, este não pode ser alterado para se referir a um outro objecto.
-
Você não pode ter referências NULL.
-
Uma referência const pode se referir a um int const. É feito com uma variável temporária com o valor da const
int i = 3; //integer declaration int * pi = &i; //pi points to the integer i int& ri = i; //ri is refers to integer i – creation of reference and initialization
A referência é um ponteiro implícito. Basicamente, você pode alterar o valor dos pontos de referência para, mas você não pode mudar a referência ao ponto para outra coisa. Então, meus 2 centavos é que, se você só quer mudar o valor de um parâmetro passá-lo como uma referência, mas se você precisar alterar o parâmetro para apontar para um objeto diferente passá-lo usando um ponteiro.
Considere C # é a chave. O compilador requer que o chamador de um método para aplicar a palavra-chave para quaisquer argumentos para fora, mesmo que ele sabe já se eles são. Este destina-se a melhorar a legibilidade. Embora com IDEs modernas eu estou inclinado a pensar que este é um trabalho para a sintaxe (ou semântica) destacando.
passar por referência const a menos que haja uma razão que deseja alterar / manter o conteúdo que você está passando na.
Este será o método mais eficiente na maioria dos casos.
Certifique-se de usar const em cada parâmetro que não deseja a mudança, o que não só protege-lo de fazer algo estúpido na função, ele dá uma boa indicação para outros usuários que a função faz ao passado em valores. Isto inclui fazer uma const ponteiro quando você quer apenas para o que está de mudança apontou para ...
Ponteiros:
- Pode ser atribuído
nullptr
(ouNULL
). - No site de chamada, você deve usar
&
se o seu tipo não é um ponteiro em si, fazendo explicitamente você está modificando seu objeto. - Os ponteiros podem ser rebote.
Referências:
- não pode ser nulo.
- Uma vez ligado, não pode mudar.
- Os chamadores não precisam explicitamente
&
uso. Este é considerado às vezes ruim porque você deve ir para a implementação da função para ver se o parâmetro é modificado.
Uma referência é semelhante a um ponteiro, exceto que você não precisa usar um prefixo * para acessar o valor referido pela referência. Além disso, não pode ser feita uma referência para se referir a um objeto diferente após a sua inicialização.
As referências são particularmente útil para especificar os argumentos da função.
Para obter mais informações, consulte "Uma Turnê C ++" por "Bjarne Stroustrup" (2014) Páginas 11-12