ponteiros não opcionais vs. referências não const em C ++


12

Em Outros recursos do C ++, argumentos de referência do Guia de estilos do Google C ++ , li que referências não-const não devem ser usadas.

Todos os parâmetros passados ​​por referência devem ser rotulados como const.

É claro que observar chamadas de função que usam referências como argumentos é absolutamente confuso para programadores em C, mas C e C ++ são linguagens diferentes agora. Se um parâmetro de saída for necessário , o uso de um ponteiro para um parâmetro de saída necessário pode fazer com que todo o corpo da função seja ignorado, o que dificulta a implementação de uma função (aumenta formalmente a complexidade ciclomática e a profundidade de uma função).

Gostaria de tornar o código C ++ o mais fácil de entender / manter possível, por isso geralmente estou interessado em ler os guias de estilo de codificação. Mas, para adaptar as melhores práticas em uma equipe, acho que entender a lógica por trás dos elementos do guia de estilo é um fator importante.

As referências não constantes são realmente tão ruins? A proibição é apenas específica do Google ou é uma regra comumente aceita? O que justifica o esforço extra para implementar parâmetros de saída como ponteiros?


2
"usar um ponteiro para fazer com que todo o corpo da função seja pulado" er, o que?
catraca aberração

@ratchetfreak Eu tentei esclarecer isso. Admito que funções como essa podem mostrar algumas falhas de design. Um ponteiro é sempre formalmente opcional, portanto deve ser verificado antes de retirá-lo da referência.
Wolf

4
O guia de estilo C ++ do Google é bastante retroativo. Na minha opinião subjetiva, deve ser queimado.
Siyuan Ren 5/10

Quanto a este item em particular, acho que a lógica é que forçar os programadores a escrever um e comercial quando os argumentos podem ser alterados mostra uma intenção mais clara.
Siyuan Ren 5/10

4
O Google Style Guide foi escrito como era para oferecer suporte a códigos homogêneos em projetos herdados do Google. Se você não estiver trabalhando em projetos herdados (que foram escritos com este guia de estilo desde o início), provavelmente não deve usá-lo (ele especifica muitas regras que não são boas para o novo código (c ++ 11, c ++ 14 , c ++ 17)).
Utnapishtim

Respostas:


18

A lógica por trás do guia de estilo do Google é simplesmente deixar claro no site de chamada de uma função se um parâmetro é um parâmetro de entrada ou um parâmetro de saída. (Veja aqui para discussão adicional.) Outros idiomas definem parâmetros explícitos por design; C #, por exemplo, tem uma outpalavra - chave que deve ser usada no site de chamada . Como o C ++ não o torna explícito, o Google optou por usar const ref. versus ponteiro para deixar claro.

Isso é apenas uma regra do Google? Não, mas duvido que seja muito difundido. Acho que não vi isso fora do guia de estilo e dos grupos do Google que aderem explicitamente a partes do guia de estilo do Google. (Por exemplo, gostei da ideia quando li o guia de estilo do Google anos atrás e o usei para alguns dos meus códigos.)

Em particular, as Diretrizes Principais do C ++ recém-anunciadas preferem valores de retorno aos parâmetros de saída para (quase) tudo e usam refs não-constantes para o resto. O uso de ponteiros e referências pelo Google pode tornar os parâmetros de saída mais claros, mas os valores de retorno ainda são mais claros. Agora que o C ++ 11 possui movimentos padronizados (referências de rvalue,, &&para fazer retornos de muitos tipos baratos) e tuplas (permitindo uma maneira fácil de retornar vários valores), muitos dos casos de uso de parâmetros out já não se aplicam.

As Diretrizes Principais do C ++ têm alguns grandes nomes (Bjarne Stroustrup, Herb Sutter), são suportadas pela Microsoft e adotam os recursos mais recentes do C ++ (ao contrário do guia de estilos do Google), então espero que suas recomendações sejam mais populares que as do Google.


Obrigado pela sua resposta (também pela breve excursão ao C #). A revisão fácil é, obviamente, um ponto importante, especialmente em projetos de código aberto. Com retornos baratos em C ++ moderno, essas considerações perderão sua importância. Com o software legado mais antigo e os compiladores antigos, ainda pode ser útil.
Wolf

Não esqueci, mas as Diretrizes Principais do C ++ não são tão rápidas de obter. É interessante que a Filosofia mostre a lógica por trás das regras e também uma visão modernizada da programação ("Expressar idéias diretamente no código" se parece um pouco com o Zen do python) como uma maneira de se comunicar.
Lobo5 /

Suplemento: link direto para a seção Filosofia das Diretrizes de Código C ++.
Wolf

1

Existem 2 opções para lidar com um ponteiro inválido passado, primeira verificação e retorno antecipado ou que seja um comportamento indefinido (se você se importa mais com velocidade do que com robustez).

A verificação é tão simples quanto:

void foo(void* buffer){
    if(buffer == nullptr)
        return;

    //actually foo

    // note no increase in indentation required

}

Esse tipo de verificação geralmente é aceito como uma verificação de parâmetro. Se você vir o código, é bastante claro que espera que um ponteiro não nulo seja passado e retorne mais cedo, caso contrário. Isso permite que você não se preocupe tanto com ponteiros inválidos.


Bem, pensei sobre esse padrão e acho absolutamente razoável. Infelizmente, não parece tão claro quanto assert(buffer);sabendo que a afirmação está ativa apenas para a versão de depuração, às vezes desejo ter uma rt_assert(buffer);que lança uma exceção. A indentação da returnaparência é um pouco perigosa ... BTW: seu trecho de código é uma boa ilustração da minha pergunta sobre ponteiros para saída.
Wolf

1

Tudo se resume à sua observação If an output parameter is required.

O único local em que uma assinatura de função é necessária para ter um parâmetro de saída é quando ela é especificada por uma API externa e, nesse caso, você apenas envolve a API externa em algo que garante que sempre haja um pontapé válido.

Internamente, você evita os parâmetros de saída estendendo o tipo de retorno para ser um composto de todas as "saídas"


Quer dizer, o único lugar em que não posso fornecer um ponteiro não obrigatório? É verdade, mas não tenho certeza se sua regra The only place where...é realmente aplicável a todos os casos. O que você sugere é: evite parâmetros de saída nas funções de seus próprios programas. Verdadeiro para novos programas.
Wolf

1
Sim, parâmetros de saída evitar, preferem tipos de retorno compostas, editado para fazer essa clara
Caleth
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.