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

?
Foi útil?

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:

  1. 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
  2. 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.

  3. 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 ...
  4. 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
    

enter descrição da imagem aqui

enter descrição da imagem aqui

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 (ou NULL).
  • 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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top