¿Qué tan importante es inicializar una variable?

9

¿Qué tan importante es inicializar variables?

¿La inicialización adecuada evita pérdidas de memoria o tiene ventajas de rendimiento?

Vivek
fuente
14
Depende del idioma. En algunos idiomas es bastante importante evitar errores, en el resto es simplemente algo bueno para ayudar a la legibilidad.
Telastyn
Gracias Telastyn por tu aporte. ¿Puedes poner un caso donde se vuelve importante dependiendo del idioma?
Vivek
44
C ++ es el notorio aquí. En la depuración, los nullcompiladores comunes inicializan las variables locales a 0 (o ), pero son basura aleatoria cuando se compilan para su lanzamiento. (aunque mi conocimiento de C ++ es de hace ~ 10 años, las cosas pueden haber cambiado)
Telastyn
Es un caso de una vez quemado, dos veces tímido. Desde que vi / tuve errores causados ​​por variables no inicializadas, especialmente punteros, se ha convertido en un hábito. Para el rendimiento, generalmente es irrelevante. Para pérdidas de memoria, no es realmente un problema.
Mike Dunlavey
1
@Telastyn es peor que eso. El comportamiento indefinido no se limita al estado basura, cualquier cosa puede suceder. El compilador puede suponer que las rutas que leen variables no inicializadas son inalcanzables y eliminan los efectos "no relacionados" que ocurren en el camino.
Caleth

Respuestas:

7

Las variables no inicializadas hacen que un programa no sea determinista. Cada vez que se ejecuta el programa, puede comportarse de manera diferente. Los cambios no relacionados con el entorno operativo, la hora del día, la fase de la luna y las permutaciones de tales afectan cómo y cuándo se manifiestan estos demonios. El programa puede ejecutarse un millón de veces antes de que se presente el defecto, puede hacerlo cada vez o ejecutar otro millón. Muchos problemas se atribuyen a "problemas técnicos" y se ignoran, o los informes de defectos de los clientes se cierran como "No reproducibles". ¿Con qué frecuencia ha reiniciado una máquina para 'solucionar' un problema? ¿Con qué frecuencia le ha dicho a un cliente "Nunca he visto que eso suceda, avíseme si lo ve de nuevo", con la esperanza (sabiendo) que no lo harán!

Como la reproducción de un defecto puede ser casi imposible en el entorno de prueba, es casi imposible de encontrar y corregir.

El error puede tardar años en aparecer, comúnmente en el código que se considera confiable y estable. Se presume que el defecto está en un código más reciente; rastrearlo puede llevar mucho más tiempo. Un cambio en el compilador, un cambio de compilador, incluso agregar una línea de código puede cambiar el comportamiento.

Inicializar variables tiene una gran ventaja de rendimiento, no solo porque un programa que funciona correctamente es infinitamente más rápido que uno que no lo hace, sino que los desarrolladores pasan menos tiempo buscando y reparando defectos que no deberían estar allí y más tiempo haciendo un trabajo "real".

La otra ventaja significativa de inicializar variables es que el autor original del código debe decidir a qué inicializarlas. Esto no siempre es un ejercicio trivial, y cuando no lo es, puede ser una indicación de un mal diseño.

Las pérdidas de memoria son un problema diferente, pero una inicialización adecuada no solo puede ayudar a prevenirlas, sino que también puede ayudar a detectarlas y encontrar la fuente: depende en gran medida del idioma y esa es realmente una pregunta separada que merece más exploración de la que puedo ofrecer. en esta respuesta

Editar: en algunos lenguajes (p. Ej., C #) no es posible usar variables no inicializadas, ya que el programa no compilará o informará un error cuando se ejecute, si se hace. Sin embargo, muchos lenguajes con estas características tienen interfaces para código potencialmente inseguro, por lo que se debe tener cuidado al usar tales interfaces no para introducir variables no inicializadas.

Mattnz
fuente
66
Muchos lenguajes de programación configuran automáticamente sus variables a un valor predefinido, por lo que gran parte de lo que dice aquí no es aplicable a esos idiomas.
Robert Harvey
2
Solo para reiterar lo que dijo @RobertHarvey, nada de esto es aplicable a C #. No hay una ventaja de rendimiento al inicializar sus variables cuando las declara, y es imposible usar una variable no inicializada, por lo que no puede culpar a los errores no reproducibles. (Se es posible utilizar un campo de clase sin inicializar, pero se pone conjunto a un valor predeterminado y genera una advertencia en ese caso)
Bobson
44
@mattnz: el punto es que para los lenguajes que se comportan como C # (o Java), algunos de estos consejos son engañosos o totalmente erróneos. Como una cuestión independiente del lenguaje, debe tener una respuesta agnóstica lenguaje, lo que significa que abordan lenguas, que hacen las variables mango inicializado de forma segura, así como aquellos que no lo hacen.
Bobson el
1
También agregaría que el problema de la variable no inicializada no es difícil de encontrar, ya que cualquier compilador medio decente / analizador estático advertirá sobre ellos
jk.
1
Para Java (y C # presumiblemente) la inicialización prematura de locales es innecesaria y podría generar más errores. Por ejemplo, establecer una variable en nulo antes de asignarla condicionalmente anula la capacidad del compilador de decirle que una de las rutas a través del código puede no resultar en la asignación de la variable.
JimmyJames
7

Inicializar una variable como señaló Telastyn puede evitar errores. Si la variable es un tipo de referencia, inicializarla puede evitar errores de referencia nulos en el futuro.

Una variable de cualquier tipo que tenga un valor predeterminado no nulo ocupará algo de memoria para almacenar el valor predeterminado.

Kevin
fuente
6

Intentar usar una variable no inicializada siempre es un error, por lo que tiene sentido minimizar la probabilidad de que ocurra ese error.

Probablemente, el enfoque más común que toman los lenguajes de programación para mitigar el problema es inicializar automáticamente a un valor predeterminado, por lo que al menos si olvida inicializar una variable, será algo así como 0algo diferente 0x16615c4b.

Esto resuelve un gran porcentaje de errores, si de todos modos necesita una variable inicializada a cero. Sin embargo, usar una variable que se inicializó con un valor incorrecto es tan malo como usar una que no se inicializó en absoluto. De hecho, a veces puede ser aún peor, porque el error puede ser más sutil y difícil de detectar.

Los lenguajes de programación funcional resuelven este problema no solo rechazando valores no inicializados, sino también rechazando la reasignación por completo. Eso elimina el problema y resulta que no es una restricción tan severa como podría pensar. Incluso en lenguajes no funcionales, si espera declarar una variable hasta que tenga un valor correcto para inicializarla, su código tiende a ser mucho más robusto.

En cuanto al rendimiento, probablemente sea insignificante. En el peor de los casos, con variables no inicializadas, tiene una asignación adicional y vincula algo de memoria por más tiempo del necesario. Los buenos compiladores pueden optimizar las diferencias en muchos casos.

Las pérdidas de memoria no tienen relación alguna, aunque las variables correctamente inicializadas tienden a estar dentro del alcance por un período de tiempo más corto y, por lo tanto, es menos probable que un programador pierda accidentalmente.

Karl Bielefeldt
fuente
¿Siempre? Quiere decir que "siempre" como en "¿Cómo un mensaje de Valgrind fijo hizo OpenSSL junto a inútil" marc.info/?t=114651088900003&r=1&w=2 ? ¿O te refieres al otro, el "casi siempre"?
JensG
1
Puedo pensar en tres lenguajes que permiten variables sin inicializar sin error, uno de los cuales usa tal para un propósito lingüístico.
DougM
Me interesarían los detalles. Sospecharía que, en esos casos, las variables no están realmente sin inicializar, sino que el programador las inicializa de una forma distinta a la directa en el sitio de declaración. O son asignados por algún medio indirecto antes de ser desreferenciados.
Karl Bielefeldt
5

Inicializar, implica que el valor inicial es importante. Si el valor inicial importa, entonces sí, claramente debe asegurarse de que esté inicializado. Si no importa, eso implica que se inicializará más tarde.

La inicialización innecesaria causa ciclos de CPU desperdiciados. Si bien estos ciclos desperdiciados pueden no importar en ciertos programas, en otros programas, cada ciclo es importante ya que la velocidad es una preocupación principal. Por lo tanto, es muy importante comprender cuáles son los objetivos de rendimiento y si las variables deben inicializarse o no.

Las pérdidas de memoria son un problema completamente diferente que generalmente implica una función de asignación de memoria para emitir y luego reciclar bloques de memoria. Piensa en una oficina de correos. Ve y pide un buzón. Te dan uno. Pides otro. Te dan otra. La regla es que cuando termine de usar un buzón de correo, debe devolverlo. Si olvida devolverlo, todavía piensan que lo tiene, y la caja no puede ser reutilizada por nadie más. Por lo tanto, hay un trozo de memoria atado y no se usa, y esto es lo que se conoce como pérdida de memoria. Si sigue pidiendo cajas en algún momento, se quedará sin memoria. He simplificado demasiado esto, pero esta es la idea básica.

Vista elíptica
fuente
-1 estás redefiniendo lo que significa inicialización en este contexto.
Pieter B
@Pieter B, no entiendo tu comentario. Por favor, si quiere, diga cómo estoy, "redefiniendo lo que significa inicialización en este contexto". Gracias
Vista elíptica
Lea su propia oración, es un razonamiento circular: "Inicializar, implica que el valor inicial importa. Si el valor inicial importa, entonces sí, claramente debe asegurarse de que se inicialice. Si no importa, eso implica que obtendrá inicializado más tarde ".
Pieter B
@Pieter B, algunas personas se inicializan como una regla general y no por una razón programática, es decir, inicializan si el valor inicial importa o no. ¿No es este el corazón de OQ: qué tan importante es inicializar una variable? De todos modos, has estado fuera votado aquí.
Vista elíptica
2

Como otros dijeron, depende del idioma. Pero demostraré mis ideas de Java (y Java efectivo) sobre la inicialización de variables. Estos deberían ser utilizables para muchos otros idiomas de nivel superior.

Constantes y variables de clase

Las variables de clase, marcadas con staticen Java, son como constantes. Estas variables normalmente deberían ser finales e inicializadas directamente después de la definición usando =o desde un bloque de inicializador de clase static { // initialize here }.

Campos

Como en muchos idiomas de nivel superior y scripting, los campos se asignarán automáticamente a un valor predeterminado. Para números y chareste será el valor cero. Para cadenas y otros objetos será null. Ahoranull es peligroso y debe usarse con moderación. Por lo tanto, estos campos deben establecerse en un valor válido lo antes posible. El constructor es normalmente un lugar perfecto para esto. Para asegurarse de que las variables se establecen durante el constructor y no se cambian después, puede marcarlas con la finalpalabra clave.

Intenta resistir el impulso de usar nullcomo algún tipo de bandera o valor especial. Es mejor, por ejemplo, incluir un campo específico para mantener el estado. Un campo con el nombre stateque usa los valores de unState enumeración sería una buena opción.

Parámetros del método

Como la persona que llama no verá los cambios en los valores de los parámetros (ya sea referencias a objetos o tipos básicos como enteros, etc.), los parámetros deben marcarse como final. Esto significa que los valores de la variable en sí no se pueden cambiar. Tenga en cuenta que el valor de las instancias de objeto mutable se puede cambiar, la referencia no se puede cambiar para apuntar a un objeto diferente onull aunque.

Variables locales

Las variables locales no se inicializan automáticamente; deben inicializarse antes de poder usar su valor. Un método para asegurarse de que su variable se inicialice es inicializarla directamente a algún tipo de valor predeterminado. Sin embargo, esto es algo que no deberías hacer. La mayoría de las veces el valor predeterminado no es un valor que esperaría.

Es mucho mejor definir solo la variable precisamente donde la necesita. Si la variable solo toma un valor único (lo cual es cierto para la mayoría de las variables en buen código), entonces puede marcar la variable final. Esto asegura que la variable local se asigne exactamente una vez, no cero veces o dos veces. Un ejemplo:

public static doMethod(final int x) {
    final int y; // no assignment yet, it's final so it *must* be assigned
    if (x < 0) {
        y = 0;
    } else if (x > 0) {
        y = x;
    } else {
        // do nothing <- error, y not assigned if x = 0
        // throwing an exception here is acceptable though
    }
}

Tenga en cuenta que muchos idiomas le avisarán si una variable permanece sin inicializar antes de su uso. Consulte las especificaciones de idioma y los foros para ver si no se preocupa innecesariamente.

Maarten Bodewes
fuente
1

No hay problema con las variables de inicialización.

El problema es solo cuando lee una variable que aún no se ha escrito.

Dependiendo del compilador y / o del tipo de variable, la inicialización se realiza al inicio de la aplicación. O no.

Es de uso común no confiar en la inicialización automática.

Mouviciel
fuente
0

Inicializar variables (implícita o explícitamente) es crucial. No inicializar una variable siempre es un error (sin embargo, podrían inicializarse implícitamente. Ver más abajo). Los compiladores modernos como el compilador de C # (como ejemplo) tratan esto como un error y no le permiten ejecutar el código. Una variable no inicializada es simplemente inútil y dañina. A menos que esté creando un generador de números aleatorios, espera que un código produzca un resultado determinista y reproducible. Esto solo se puede lograr si comienza a trabajar con variables inicializadas.

La pregunta realmente interesante es si una variable se inicializa automáticamente o si tiene que hacerlo manualmente. Depende del idioma utilizado. En C #, por ejemplo, los campos, es decir, "variables" a nivel de clase, siempre se inicializan automáticamente al valor predeterminado para ese tipo de variable.default(T) . Este valor corresponde a un patrón de bits que consiste en todos los ceros. Esto es parte de la especificación del lenguaje y no solo un detalle técnico de la implementación del lenguaje. Por lo tanto, puede confiar en él de manera segura. Es seguro no inicializar una variable explícitamente si (y solo si) la especificación del lenguaje establece que se inicializa implícitamente.Si desea otro valor, debe inicializar la variable explícitamente. Sin embargo; en C # las variables locales, es decir, las variables declaradas en los métodos, no se inicializan automáticamente y siempre debe inicializar la variable explícitamente.

Olivier Jacot-Descombes
fuente
2
Esta no es una pregunta específica de C #.
DougM
@ Douglas: Lo sé. No es una respuesta específica de C #, solo tomé C # como ejemplo.
Olivier Jacot-Descombes
No todos los idiomas requieren que las variables se inicialicen explícitamente. Su declaración de "no inicializar siempre es un error" es falsa y no agrega claridad a la pregunta en cuestión. es posible que desee revisar su respuesta.
DougM
@DougM: ¿Has supervisado mi frase "La pregunta realmente interesante es si una variable se inicializa automáticamente o si tienes que hacerlo manualmente"?
Olivier Jacot-Descombes
¿te refieres al enterrado a medio camino en medio de un párrafo? si. Debería haberlo hecho más prominente y agregar un calificador a su reclamo "siempre".
DougM