Pro / con: Inicializar uma variável em uma instrução condicional
-
02-07-2019 - |
Pergunta
Em C ++ você pode inicializar uma variável em uma instrução if, assim:
if (CThing* pThing = GetThing())
{
}
Por que alguém iria considerar isso ruim ou bom estilo? Quais são as vantagens e desvantagens?
Pessoalmente eu gosto deste estilo porque limita o escopo da variável pThing, por isso nunca pode ser usado acidentalmente quando é NULL. No entanto, eu não gosto que você não pode fazer isso:
if (CThing* pThing = GetThing() && pThing->IsReallySomeThing())
{
}
Se há uma maneira de fazer o trabalho acima, por favor poste. Mas se isso não é apenas possível, eu ainda gostaria de saber por quê.
Pergunta emprestado a partir daqui, tema semelhante, mas PHP.
Solução
O importante é que uma declaração em C ++ não é uma expressão.
bool a = (CThing* pThing = GetThing()); // not legit!!
Você não pode fazer tanto uma declaração e lógica booleana em uma instrução if, C ++ especificação linguagem permite especificamente uma expressão ou uma declaração.
if(A *a = new A)
{
// this is legit and a is scoped here
}
Como podemos saber se um é definida entre um termo e outro em uma expressão?
if((A *a = new A) && a->test())
{
// was a really declared before a->test?
}
morder a bala e usar um interno se. As regras de escopo são úteis e sua lógica é explícito:
if (CThing* pThing = GetThing())
{
if(pThing->IsReallySomeThing())
{
}
}
Outras dicas
Sobre as vantagens:
É sempre recomendável para definir variáveis ??quando você precisar deles, não uma linha antes. Isto é para melhorar a legibilidade do seu código, uma vez que um pode dizer o que CThing é sem rolagem e procurar onde ele foi definido.
reduzindo também espaço para um loop / if bloco, faz com que a variável a ser não referenciados após a execução do bloco de código, o que o torna um candidato para coleta de lixo (se o idioma suporte a esse recurso).
if (CThing* pThing = GetThing())
É mau estilo , porque dentro do if
você não está fornecendo uma expressão booleana. Você está fornecendo um CThing*
.
CThing* pThing = GetThing();
if (pThing != NULL)
Este é um bom estilo.
Uma razão que eu normalmente não fazer isso é por causa do erro comum de uma falta '=' em um teste condicional. Eu uso fiapos com o erro / avisos definido para pegar aqueles. Será, então grite sobre todas as atribuições dentro condicionais.
Apenas um FYI alguns dos compliers mais velhos Microsoft C ++ (Visual Studios 6 e .NET 2003 eu acho) não chegam a seguir a regra de escopo em alguns casos.
for(int i = 0; i > 20; i++) {
// some code
}
cout << i << endl;
Eu deveria estar fora de alcance, mas que foi / é um código válido. Eu acredito que foi jogado fora como um recurso, mas na minha opinião é apenas incumprimento. Não aderindo aos padrões é ruim. Assim como um desenvolvedor web sobre IE e Firefox.
Pode alguém com check VS e ver se isso ainda é válido?
Este deve não funciona no C ++ desde mesmo que ele suporta curto-circuito avaliação . Talvez Não tente o seguinte:
if ((CThing* pThing = GetThing()) && (pThing->IsReallySomeThing()))
{
}
err .. ver a resposta de Wesley Tarle
Você também pode englobar a atribuição de um conjunto extra de () para impedir que a mensagem de aviso.
Eu vejo isso como uma espécie de perigoso. O código abaixo é muito mais seguro e as chaves que encerram ainda vai limitar o âmbito da pThing da maneira que você quiser.
Estou assumindo GetThing () às vezes retorna NULL é por isso que eu coloquei essa cláusula engraçado na declaração if (). Ele impede IsReallySomething () sendo chamado em um ponteiro NULL.
{
CThing *pThing = GetThing();
if(pThing ? pThing->IsReallySomeThing() : false)
{
// Do whatever
}
}
Além disso, observe que, se você está escrevendo código C ++ você quiser fazer o aviso do compilador sobre "=" em uma declaração condicional (que não faz parte de uma declaração) um erro.
É prática de codificação aceitável e bom. No entanto, as pessoas que não vêm de um baixo nível de codificação fundo provavelmente discordar.
muitas coisas. Primeiro de tudo, descobrir ponteiros. Por favor, evitá-los por todos os meios. Use referências, opcional, unique_ptr, shared_ptr. Como o último recurso, escrever sua própria classe que lida com propriedade ponteiro e nada mais.
Use a inicialização uniforme se você pode exigir C ++ 11 (C ++ 14 preferia evitar C ++ 11 defeitos): -. Evita = vs == confusão e é mais rigorosa na verificação os argumentos, se houver algum
if (CThing thing {})
{
}
Certifique-se de implementar operator bool
para obter conversão previsível a partir CThing para bool. No entanto, tenha em mente que outras pessoas lendo o código não veria operator bool
imediatamente. chamadas explícitas método são geralmente mais legível e reconfortante. Se você pode exigir C ++ 17, o uso initializer sintaxe.
if (CThing thing {}; thing.is_good())
{
}
Se C ++ 17 não é uma opção, use uma declaração acima, se, como já foi sugerido.
{
CThing thing {};
if (thing.is_good())
{
}
}