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?

Lobo
fonte
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.

Josh Kelley
fonte
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.

catraca arrepiante
fonte
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"

Caleth
fonte
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