universitaria tipos porque los libro importante formativa evaluar evaluacion educativa delos criterios aprendizajes alumnos c++ macros preprocessor-directive

c++ - tipos - ¿Qué es una doble evaluación y por qué debería evitarse?



tipos de evaluacion pdf (4)

Estaba leyendo eso en C ++ usando macros como

#define max(a,b) (a > b ? a : b)

puede resultar en una ''doble evaluación''. ¿Puede alguien darme un ejemplo de cuándo ocurre una doble evaluación y por qué es mala?

PD: Sorprendentemente no pude encontrar ninguna explicación detallada cuando busqué en Google, excepto por un ejemplo en Clojure (que no puedo entender).


Considera la siguiente expresión:

x = max(Foo(), Bar());

Donde Foo y Bar son así:

int Foo() { // do some complicated code that takes a long time return result; } int Bar() { global_var++; return global_var; }

Entonces en la expresión max original se expande como:

Foo() > Bar() ? Foo() : Bar();

En cualquier caso, Foo o Bar se ejecutarán dos veces. De este modo, tomar más tiempo de lo necesario o cambiar el programa de estado más de la cantidad esperada de veces. En mi ejemplo de Bar simple, no devuelve el mismo valor de forma consistente.


El lenguaje de macros en C y C ++ es procesado por un analizador dedicado en la etapa de ''preprocesamiento''; los tokens se traducen y la salida se alimenta a la corriente de entrada del analizador propiamente dicho. #define y #include tokens no son reconocidos por los analizadores C o C ++.

Esto es importante porque significa que cuando se dice que una macro está "expandida" significa literalmente eso. Dado

#define MAX(A, B) (A > B ? A : B) int i = 1, j = 2; MAX(i, j);

lo que el analizador de C ++ ve es

(i > j ? i : j);

Sin embargo, si utilizamos la macro con algo más complejo, ocurre la misma expansión:

MAX(i++, ++j);

se expande a

(i++ > ++j ? i++ : ++j);

Si pasamos algo que hace una llamada de función:

MAX(f(), g());

esto se expandirá a

(f() > g() ? f() : g());

Si el compilador / optimizador puede demostrar que f() no tiene efectos secundarios, lo tratará como

auto fret = f(); auto gret = g(); (fret > gret) ? fret : gret;

Si no puede, tendrá que llamar f () yg () dos veces, por ejemplo:

#include <iostream> int f() { std::cout << "f()/n"; return 1; } int g() { std::cout << "g()/n"; return 2; } #define MAX(A, B) (A > B ? A : B) int main() { MAX(f(), g()); }

Demostración en vivo: http://ideone.com/3JBAmF

Del mismo modo, si estuviéramos llamando a una función extern , el optimizador no podrá evitar llamar a la función dos veces .


b ocurren dos veces en la definición de macro. Entonces, si lo usa con argumentos que tienen efectos secundarios, los efectos secundarios se ejecutan dos veces.

max(++i, 4);

devolverá 6 si i = 4 antes de la llamada. Como no es el comportamiento esperado, debe preferir funciones en línea para reemplazar tales macros como max .


Imagina que escribiste esto:

#define Max(a,b) (a < b ? b : a) int x(){ turnLeft(); return 0; } int y(){ turnRight(); return 1; }

luego lo llamó así:

auto var = Max(x(), y());

¿Sabes que turnRight() se ejecutará dos veces? Esa macro, Max se expandirá a:

auto var = (x() < y() ? y() : x());

Después de evaluar la condición x() < y() , el programa toma la rama requerida entre y() : x() : en nuestro caso true , que llama a y() por segunda vez . Véalo en vivo en Coliru .

En pocas palabras, al pasar una expresión como argumento a su macro de función , Max evaluará potencialmente esa expresión dos veces, porque la expresión se repetirá donde sea que el macroparámetro que adopte se use en la definición de la macro. Recuerde, las macros son manejadas por el preprocesador .

Entonces, la línea de fondo es, no use macros para definir una función (en realidad una expresión en este caso) simplemente porque quiere que sea genérica , mientras que se puede hacer de manera efectiva usando una plantilla de función

PD: C ++ tiene una función de plantilla std::max .