Orden de evaluación de argumentos usando std::cout

Resuelto FailedDev asked hace 12 años • 5 respuestas

Hola a todos, hoy me topé con este fragmento de código y no sé qué sucede exactamente y, más concretamente, en qué orden:

Código:

#include <iostream>

bool foo(double & m)
{
    m = 1.0;
    return true;
}

int main()
{
    double test = 0.0;
    std::cout << "Value of test is : \t" << test << "\tReturn value of function is : " << foo(test) <<  "\tValue of test : " << test << std::endl;
    return 0;
}

La salida es:

Value of test is :      1       Return value of function is : 1 Value of test : 0

Al ver esto, asumiría que de alguna manera el argumento más a la derecha se imprime antes de la llamada a la función. ¿Entonces esta es una evaluación de derecha a izquierda? Sin embargo, durante la depuración parece que la función se llama antes de la salida, que es lo que esperaría. Estoy usando Win7 y MSVS 2010. ¡Se agradece cualquier ayuda!

FailedDev avatar Oct 11 '11 03:10 FailedDev
Aceptado

El orden de evaluación de los elementos en una expresión no está especificado (excepto en algunos casos muy particulares, como los operadores &&y ||y el operador ternario, que introducen puntos de secuencia ); por lo que no se garantiza que testse evalúe antes o después foo(test)(lo que lo modifica).

Si su código se basa en un orden de evaluación particular, el método más simple para obtenerlo es dividir su expresión en varias declaraciones separadas.

Matteo Italia avatar Oct 10 '2011 20:10 Matteo Italia

La respuesta a esta pregunta cambió en C++17.

La evaluación de operadores sobrecargados ahora se secuencia de la misma manera que para los operadores integrados (C++17 [over.match.oper]/2).

Además, los <<operadores >>de subíndice y ahora tienen el operando izquierdo secuenciado antes del derecho, y la expresión postfijo de una llamada de función se secuencia antes de la evaluación de los argumentos.

(Los otros operadores binarios conservan su secuencia anterior, por ejemplo, +todavía no está secuenciado).

Entonces el código en la pregunta ahora debe generar Value of test is : 0 Return value of function is : 1 Value of test : 1. Pero el consejo "No hagas esto" sigue siendo razonable, dado que a todos les llevará algún tiempo actualizar a C++17.

M.M avatar May 16 '2018 02:05 M.M

El orden de evaluación no se especifica. No es de izquierda a derecha, de derecha a izquierda ni de ninguna otra cosa.

No hagas esto.

John Dibling avatar Oct 10 '2011 20:10 John Dibling

El orden de evaluación no se especifica, consulte http://en.wikipedia.org/wiki/Sequence_point

Esta es la misma situación que el ejemplo con el ejemplo operador+:

Considere dos funciones f()y g(). En C y C++, el +operador no está asociado con un punto de secuencia y, por lo tanto, en la expresión f()+g()es posible que f()o g()se ejecute primero.

duncan avatar Oct 10 '2011 21:10 duncan

la referencia de C++ explica muy bien por qué eso nunca debería hacerse (está causando un UB o un comportamiento indefinido) https://en.cppreference.com/w/cpp/language/operator_incdec

#include <iostream>

int main()
{
    int n1 = 1;
    int n2 = ++n1;
    int n3 = ++ ++n1;
    int n4 = n1++;
//  int n5 = n1++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    std::cout << "n1 = " << n1 << '\n'
              << "n2 = " << n2 << '\n'
              << "n3 = " << n3 << '\n'
              << "n4 = " << n4 << '\n';
}

Notas

Debido a los efectos secundarios involucrados, los operadores integrados de incremento y decremento deben usarse con cuidado para evitar comportamientos indefinidos debido a violaciones de las reglas de secuenciación.


y en la sección relacionada con reglas de secuenciación puedes leer lo siguiente:

Comportamiento indefinido:

1) Si un efecto secundario en un objeto escalar no está secuenciado en relación con otro efecto secundario en el mismo objeto escalar, el comportamiento no está definido.

i = ++i + 2;       // undefined behavior until C++11
i = i++ + 2;       // undefined behavior until C++17
f(i = -2, i = -2); // undefined behavior until C++17
f(++i, ++i);       // undefined behavior until C++17, unspecified after C++17
i = ++i + i++;     // undefined behavior

2) Si un efecto secundario en un objeto escalar no está secuenciado en relación con un cálculo de valor utilizando el valor del mismo objeto escalar, el comportamiento no está definido.

cout << i << i++; // undefined behavior until C++17
a[i] = i++;       // undefined behavior until C++17
n = ++i + i;      // undefined behavior 
ΦXocę 웃 Пepeúpa ツ avatar Feb 06 '2020 13:02 ΦXocę 웃 Пepeúpa ツ