2008-09-25 6 views
15

En C++ se puede inicializar una variable en una sentencia if, así:Pro/acondicionado: La inicialización de una variable en una instrucción condicional

if (CThing* pThing = GetThing()) 
{ 
} 

¿Por qué uno considere esto bueno o malo el estilo? ¿Cuáles son los beneficios y desventajas?

Personalmente, me gusta este estilo porque limita el alcance de la variable pThing, por lo que nunca se puede usar accidentalmente cuando es NULL. Sin embargo, no me gusta que no se puede hacer esto:

if (CThing* pThing = GetThing() && pThing->IsReallySomeThing()) 
{ 
} 

Si hay una manera de hacer el trabajo anterior, por favor enviar. Pero si eso no es posible, me gustaría saber por qué.

Question borrowed from here, similar topic but PHP.

Respuesta

18

Lo importante es que una declaración en C++ no es una expresión.

bool a = (CThing* pThing = GetThing()); // not legit!! 

No se puede hacer tanto una declaración y la lógica booleana en una sentencia if, lenguaje C++ específicamente Spec permite ya sea una expresión o una declaración.

if(A *a = new A) 
{ 
    // this is legit and a is scoped here 
} 

¿Cómo podemos saber si a se define entre un término y otro en una expresión?

if((A *a = new A) && a->test()) 
{ 
    // was a really declared before a->test? 
} 

Muerde la viñeta y usa una if interna. Las reglas de alcance son útiles y su lógica es explícita:

if (CThing* pThing = GetThing()) 
{ 
    if(pThing->IsReallySomeThing()) 
    { 
    } 
} 
+1

"(A * a = new A) && a-> test()" Esto no es C++ estándar. (-1) –

+0

Aceptaré esta respuesta por la verbosidad técnica. La discusión sobre cuál es mejor es de hecho altamente subjetiva, prefiero el estilo de mi publicación inicial, pero mi DT no quiere que lo use, así que no lo hago. Siempre puedo usar un par de corchetes adicionales para limitar el alcance como un compromiso. – steffenj

2

Este debe no funciona en C++ desde a pesar de que es compatible con short circuiting evaluation. Tal vez no intenta lo siguiente:

if ((CThing* pThing = GetThing()) && (pThing->IsReallySomeThing())) 
{ 
} 

err .. ver Wesley Tarle's answer

+0

Lo intentaré ... recuerdo que probé todo tipo de colocación de corchetes pero ninguno funcionaría, aunque los errores del compilador cambiaron mucho dependiendo de los corchetes. – steffenj

+0

"evaluación de cortocircuito" ... hasta ahora he conocido esto como "anticipación". Este es nuevo para mí. – steffenj

2

Una razón por la que no suelo hacer esto es debido al error común de una perdida '=' en un condicional prueba. Uso pelusa con el error/advertencias establecidos para capturarlos. Luego gritará sobre todas las asignaciones dentro de condicionales.

4

Sobre las ventajas:

Siempre es recomendable para definir las variables de la primera vez que los necesita, no una línea antes. Esto es para una mejor legibilidad de su código, ya que uno puede saber qué es CThing sin desplazarse y buscar donde se definió.

Al reducir el alcance a un bloque loop/if, la variable no se referencia después de la ejecución del bloque de código, lo que lo convierte en candidato para Garbage Collection (si el lenguaje admite esta función).

2

Solo un FYI algunos de los antiguos cumplidores de C++ de Microsoft (creo que Visual Studios 6 y .NET 2003) no siguen la regla del alcance en algunos casos.

for(int i = 0; i > 20; i++) { 
    // some code 
} 

cout << i << endl; 

Debería estar fuera de alcance, pero ese era/es código válido. Creo que se jugó como una característica, pero en mi opinión es simplemente incumplimiento. No cumplir con los estándares es malo. Solo como desarrollador web sobre IE y Firefox.

¿Alguien con VS puede verificar si sigue siendo válido?

+1

Es una opción del compilador, "aplicar el alcance en la declaración" o algo así. –

+2

Sí, es/Zc: forScope- "forzar la conformidad en el alcance del lazo". Al menos en VS 2008. –

+0

Gracias por marcar chicos. Supongo que está en (rompiendo alcance) por defecto? –

0

También puede adjuntar la asignación en un conjunto adicional de() para evitar el mensaje de advertencia.

0

Veo eso como algo peligroso. El siguiente código es mucho más seguro y las llaves adjuntas aún limitarán el alcance de la manera que desee.

Supongo que GetThing() a veces devuelve NULL, por lo que pongo esa cláusula divertida en la declaración if(). Impide que se llame a IsReallySomething() en un puntero NULL.

{ 
    CThing *pThing = GetThing(); 
    if(pThing ? pThing->IsReallySomeThing() : false) 
    { 
    // Do whatever 
    } 
} 
+2

C++ tiene una evaluación de cortocircuito, por lo que "si (pThing && pthing-> IsReallySomeThing())" ya garantiza que IsReallySomeThing() no se invocará si pThing es nulo. –

+0

De acuerdo con Derek: verdadero/falso en a?: Siempre se hace mejor como ||/&& –

0

Observe también que si estás escribiendo código C++ desea hacer el compilador advertencia sobre "=" en una sentencia condicional (que no es parte de una declaración) un error.

0

Es una buena y aceptable práctica de codificación. Sin embargo, las personas que no provienen de un fondo de codificación de bajo nivel probablemente estarían en desacuerdo.

3
if (CThing* pThing = GetThing()) 

Es mal estilo, porque dentro de la if no va a proporcionar una expresión booleana. Está proporcionando un CThing*.

CThing* pThing = GetThing(); 
if (pThing != NULL) 

Este es un buen estilo.

Cuestiones relacionadas