Saltar al contenido
Topos Uranos

Asignación, efectos secundarios y comportamiento indefinido

Resumen

Una expresión de C++ puede hacer dos cosas distintas: dar un valor y cambiar el estado del programa. x + 1 solo da un valor; x = 7 da un valor y, además, cambia x; x++ da el valor que x tenía y deja en x otro. Esta clase estudia esa diferencia entre el valor y el efecto de una expresión: la asignación como expresión, la asignación compuesta, el incremento y el decremento en sus formas prefija y sufija, y el orden en que se evalúan las partes de una expresión, que la norma fija solo en parte. De ello se sigue la pregunta que ordena el resto de la clase: qué promete la norma acerca de un programa. La respuesta es un catálogo de cuatro grados, del comportamiento definido al indefinido, que reúne todos los casos vistos hasta aquí y dice, para cada uno, qué lo detecta (el compilador, el detector, la biblioteca) y qué no lo detecta nadie.

Objetivos de aprendizaje

  1. Distinguir el valor de una expresión de su efecto secundario en asignaciones, incrementos y llamadas.
  2. Predecir el resultado de x++ y ++x usados como valor, y seguir a mano un programa con asignaciones compuestas.
  3. Reconocer expresiones que modifican dos veces una variable, o que la leen y la modifican, sin un orden fijado por la norma, y reescribirlas en sentencias separadas.
  4. Clasificar una construcción como definida, definida por la implementación, no especificada o indefinida, con un ejemplo de cada clase.
  5. Decir, para cada comportamiento indefinido del catálogo, si lo advierte el compilador, si lo detiene el detector o la biblioteca, o si no lo detecta ninguno.

El valor y el efecto

La clase Aritmética en C++ estudió la expresión como un árbol que se reduce a un valor: 2 + 3 * 4 vale 14, y calcularlo no cambia nada fuera de la expresión misma. La clase Relaciones y lógica en C++ hizo lo mismo con las condiciones, cuyo valor es true o false. Ahora bien, hay expresiones que, además de dar un valor, dejan una huella en el estado del programa: cambian el valor de una variable, escriben en la pantalla o leen de la entrada. Esa huella se llama efecto secundario, o simplemente efecto, y la palabra «secundario» no quiere decir que importe menos: en x = 7 el efecto, que x pase a valer 7, es justamente lo que se busca.

Si esto es así, toda expresión debe leerse con dos preguntas: qué da y qué hace. Tres ejemplos fijan la distinción. count + 1 da el siguiente de count y no hace nada: count conserva su valor. count = 9 da 9 y hace que count valga 9. std::println("hola") es también una expresión, una llamada a una función, y lo que importa de ella es su efecto: escribir una línea. Las funciones propias se estudiarán en la clase Funciones en C++, y allí la distinción reaparecerá: una función que solo calcula su resultado es más fácil de entender y de probar que una que, además, cambia algo fuera de ella.

Una sentencia como count + 1; es C++ válido: se calcula el valor y se descarta, de modo que no sirve de nada, y GCC lo advierte con -Wunused-value. Una sentencia de expresión tiene sentido por su efecto. De ello se sigue que las expresiones con efecto son las que mueven el programa, y también las que exigen cuidado, porque el efecto ocurre en algún momento, y ese momento no siempre es el que el lector supone.