c++ c++11 expression undefined-behavior

Con C++ 11, ¿es un comportamiento indefinido escribir f(x++), g(x++)?



c++11 expression (3)

Depende.

Primero, supongamos que x++ por sí mismo no invoca un comportamiento indefinido. Piense en el desbordamiento firmado, el incremento de un puntero pasado-final o el operador post-incremento-incremento podría ser definido por el usuario).
Además, supongamos que invocar f() g() con sus argumentos y destruir los temporales no invoca un comportamiento indefinido.
Son muchas suposiciones, pero si se rompen, la respuesta es trivial.

Ahora, si la coma es el operador de coma incorporado, la coma en una lista de iniciación armada, o la coma en una lista de inicialización de mem, los lados izquierdo y derecho se secuencian antes o después de la otra (y sabes cuál), así que no interfieras, haciendo que el comportamiento esté bien definido.

struct X { int f, g; explicit X(int x) : f(x++), g(x++) {} }; // Demonstrate that the order depends on member-order, not initializer-order: struct Y { int g, f; explicit Y(int x) : f(x++), g(x++) {} }; int y[] = { f(x++), g(x++) };

De lo contrario, si x++ invoca una sobrecarga de operador definida por el usuario para postfix-increment, tiene una secuencia indeterminada de las dos instancias de x++ y, por lo tanto, un comportamiento no especificado.

std::list<int> list{1,2,3,4,5,6,7}; auto x = begin(list); using T = decltype(x); void h(T, T); h(f(x++), g(x++)); struct X { X(T, T) {} } X(f(x++), g(x++));

Y en el caso final, se obtiene un comportamiento no definido en toda regla, ya que los dos incrementos de x postfix de x tienen secuencia.

int x = 0; void h(int, int); h(f(x++), g(x++)); struct X { X(int, int) {} } X(f(x++), g(x++));

Estaba leyendo esta pregunta:

Comportamiento indefinido y puntos de secuencia.

y, específicamente, la respuesta de C ++ 11 , y entiendo la idea de "secuenciar" las evaluaciones. Pero - ¿hay suficiente secuencia cuando escribo:

f(x++), g(x++); ?

Es decir, ¿tengo la garantía de que f() obtiene el valor original de x g() obtiene una x incrementada una vez?

Notas para los nitpickers:

  • Supongamos que el operator++() tiene un comportamiento definido (incluso si lo hemos anulado) y también lo hace f() g() , que no se lanzarán excepciones, etc., esta pregunta no es sobre eso.
  • Supongamos que el operator,() no ha sido sobrecargado.

No, no es un comportamiento indefinido.

De acuerdo con este orden de evaluación y la referencia de secuenciación, el lado izquierdo de la coma se evalúa por completo antes del lado derecho (ver rule 9):

9) Cada cálculo de valor y efecto secundario del primer argumento (izquierda) del operador de coma incorporado, se secuencia antes de cada cálculo de valor y efecto secundario del segundo argumento (derecho).

Eso significa que una expresión como f(x++), g(x++) no está indefinida.

Tenga en cuenta que esto solo es válido para el operador de coma incorporado .


No, el comportamiento está definido. Para citar C ++ 11 (n3337) [expr.comma/1] :

Un par de expresiones separadas por una coma se evalúa de izquierda a derecha; la expresión de la izquierda es una expresión de valor descartado (Cláusula [expr]). Cada cálculo de valor y efecto secundario asociado con la expresión izquierda se secuencia antes de cada cálculo de valor y efecto secundario asociado con la expresión derecha.

Y tomo "cada" para significar "cada" 1 . La evaluación del segundo x++ no puede ocurrir antes de que se complete la secuencia de llamadas a f y f vuelva. 2

1 Las llamadas de Destructor no están asociadas con subexpresiones, solo con expresiones completas. Así que verás los ejecutados en orden inverso a la creación de objetos temporales al final de la expresión completa.
2 Este párrafo solo se aplica a la coma cuando se utiliza como operador. Cuando la coma tiene un significado especial (por ejemplo, al designar una secuencia de argumento de llamada de función), esto no se aplica.