¿Por qué declarar una variable en una línea y asignarla a la siguiente?

98

A menudo veo en el código C y C ++ la siguiente convención:

some_type val;
val = something;

some_type *ptr = NULL;
ptr = &something_else;

en lugar de

some_type val = something;
some_type *ptr = &something_else;

Inicialmente asumí que este era un hábito que quedaba de los días en que tenías que declarar todas las variables locales en la parte superior del alcance. Pero he aprendido a no descartar tan rápidamente los hábitos de los desarrolladores veteranos. Entonces, ¿hay una buena razón para declarar en una línea y asignar después?

    
pregunta Jonathan Sterling 07.05.2011 - 22:30
fuente

7 respuestas

87

C

En C89 todas las declaraciones tenían que estar al principio de un ámbito ( { ... } ), pero este requisito se eliminó rápidamente (primero con las extensiones del compilador y luego con el estándar).

C ++

Estos ejemplos no son los mismos. some_type val = something; llama al constructor de copia, mientras que val = something; llama al constructor predeterminado y luego a la función operator= . Esta diferencia es a menudo crítica.

Hábitos

Algunas personas prefieren declarar primero las variables y luego definirlas, en caso de que estén reformateando su código más adelante con las declaraciones en un lugar y la definición en otro.

Sobre los punteros, algunas personas solo tienen el hábito de inicializar cada puntero a NULL o nullptr , sin importar lo que hagan con ese puntero.

    
respondido por el orlp 07.05.2011 - 22:35
fuente
26

Has etiquetado tus preguntas C y C ++ al mismo tiempo, mientras que la respuesta es significativamente diferente en estos idiomas.

En primer lugar, la redacción del título de su pregunta es incorrecta (o, más precisamente, irrelevante para la pregunta en sí). En ambos ejemplos, la variable se declara y define simultáneamente, en una línea. La diferencia entre sus ejemplos es que en el primero las variables se dejan sin inicializar o inicializadas con un valor ficticio y luego se asignan a valor significativo más tarde. En el segundo ejemplo, las variables se inicializan de inmediato.

En segundo lugar, en lenguaje C ++, como @nightcracker señaló en su respuesta, estas dos construcciones son semánticamente diferentes. El primero se basa en la inicialización y el segundo en la asignación. En C ++, estas operaciones son sobrecargables y, por lo tanto, pueden dar lugar a resultados diferentes (aunque se puede observar que producir sobrecargas no equivalentes de inicialización y asignación no es una buena idea).

En el lenguaje C estándar original (C89 / 90) es ilegal declarar variables en la mitad del bloque, por lo que es posible que vea las variables declaradas sin inicializar (o inicializadas con valores ficticios) al comienzo del bloque y luego se le asignan valores significativos más adelante, cuando esos valores significativos estén disponibles.

En el lenguaje C99, está bien declarar variables en la mitad del bloque (como en C ++), lo que significa que el primer enfoque solo es necesario en algunas situaciones específicas cuando el inicializador no se conoce en el punto de declaración. (Esto también se aplica a C ++).

    
respondido por el AnT 07.05.2011 - 22:47
fuente
13

Creo que es un viejo hábito, sobrante de los tiempos de "declaración local". Y por lo tanto, como respuesta a tu pregunta: No, no creo que haya una buena razón. Nunca lo hago yo mismo.

    
respondido por el CornflakesDK 07.05.2011 - 22:35
fuente
4

Dije algo al respecto en mi respuesta a una pregunta de Helium3 .

Básicamente, digo que es una ayuda visual para ver fácilmente qué ha cambiado.

if (a == 0) {
    struct whatever *myobject = 0;
    /* did 'myobject' (the pointer) get assigned?
    ** or was it '*myobject' (the struct)? */
}

y

if (a == 0) {
    struct whatever *myobject;
    myobject = 0;
    /* 'myobject' (the pointer) got assigned */
}
    
respondido por el pmg 07.05.2011 - 22:42
fuente
4

Las otras respuestas son bastante buenas. Hay algo de historia alrededor de esto en C. En C ++ hay una diferencia entre un constructor y un operador de asignación.

Me sorprende que nadie mencione el punto adicional: mantener las declaraciones separadas del uso de una variable a veces puede ser mucho más legible.

Hablando visualmente, al leer el código, los artefactos más mundanos, como los tipos y los nombres de las variables, no son lo que te llama la atención. Son las declaraciones las que más le interesan, pasan la mayor parte del tiempo mirando, y por eso hay una tendencia a echar un vistazo al resto.

Si tengo algunos tipos, nombres y tareas en el mismo espacio reducido, es un poco de sobrecarga de información. Además, significa que algo importante está sucediendo en el espacio que normalmente observo.

Puede parecer un poco contraintuitivo, pero esta es una instancia en la que hacer que su fuente ocupe más espacio vertical puede mejorarlo. Veo esto como una razón por la que no debes escribir líneas atestadas que hacen cantidades locas de aritmética y asignación de punteros en un espacio vertical estrecho, solo porque el lenguaje te permite salirse con la suya, no significa que debas hacerlo todo el tiempo :-)

    
respondido por el asveikau 08.05.2011 - 00:01
fuente
2

En C, esta era la práctica estándar porque las variables debían declararse al inicio de la función, a diferencia de en C ++, donde podría declararse en cualquier parte del cuerpo de la función que se usará a partir de entonces. Los punteros se establecieron en 0 o NULL, porque solo se aseguró de que el puntero no apuntara a ninguna basura. De lo contrario, no puedo pensar en ninguna ventaja significativa, lo que obliga a cualquiera a hacer eso.

    
respondido por el Vite Falcon 07.05.2011 - 22:39
fuente
2

Ventajas de localizar definiciones de variables y su inicialización significativa:

  • si a las variables se les asigna habitualmente un valor significativo cuando aparecen por primera vez en el código (otra perspectiva sobre la misma cosa: retrasas su aparición hasta que un valor significativo esté disponible), entonces no hay posibilidad de se usan accidentalmente con un valor sin significado o sin inicializar (lo que puede suceder fácilmente si alguna inicialización se pasa por alto accidentalmente debido a declaraciones condicionales, evaluación de cortocircuito, excepciones, etc.)

  • puede ser más efficient

    • evita los gastos generales de configuración del valor inicial (construcción predeterminada o inicialización de algún valor centinela como NULL)
    • operator= a veces puede ser menos eficiente y requiere un objeto temporal
    • a veces (especialmente para funciones en línea) el optimizador puede eliminar algunas / todas las ineficiencias

  • minimizar el alcance de las variables a su vez minimiza el promedio número de variables al mismo tiempo en el alcance : esto

    • hace que sea más fácil realizar un seguimiento mental de las variables en el alcance, los flujos de ejecución y las declaraciones que pueden afectar esas variables, y la importación de su valor
    • al menos para algunos objetos complejos y opacos, esto reduce el uso de recursos (montón, hilos, memoria compartida, descriptores) del programa
  • a veces es más conciso, ya que no estás repitiendo el nombre de la variable en una definición y luego en una asignación significativa inicial

  • necesario para ciertos tipos, como referencias, y cuando desea que el objeto sea const

Argumentos para agrupar definiciones de variables:

  • a veces es conveniente y / o conciso para calcular el tipo de una serie de variables:

    the_same_type v1, v2, v3;

    (si el motivo es simplemente que el nombre del tipo es demasiado largo o complejo, a veces un typedef puede ser mejor)

  • a veces es conveniente agrupar variables independientemente de su uso para enfatizar el conjunto de variables (y tipos) involucrados en alguna operación:

    type v1;
    type v2; type v3;

    Esto enfatiza el carácter común del tipo y hace que sea un poco más fácil cambiarlo, al tiempo que se adhiere a una variable por línea que facilita copiar y pegar, // comentar, etc.

Como suele ser el caso en la programación, si bien puede haber un claro beneficio empírico para una práctica en la mayoría de las situaciones, la otra práctica puede ser mucho mejor en algunos casos.

    
respondido por el Tony 09.05.2011 - 11:57
fuente

Lea otras preguntas en las etiquetas