enclosed - initialize vector c++ 11
¿Las mutaciones múltiples dentro del inicializador enumeran el comportamiento indefinido? (2)
Sí, el código es válido y no tiene un comportamiento indefinido. Las expresiones en una lista de iniciadores se evalúan de izquierda a derecha y se secuencian antes de la evaluación del constructor de S
Por lo tanto, su programa debe asignar constantemente el valor 2
a la variable i
.
Citando el § 8.5.4 del Estándar C ++:
"Dentro de la lista de inicialización de una lista inicial arrinconada, las cláusulas inicializadoras, incluidas las que resultan de las expansiones de paquetes (14.5.3), se evalúan en el orden en que aparecen . Es decir, cada cómputo de valor y lado el efecto asociado con una cláusula de inicializador dada se secuencia antes de cada cálculo de valor y efecto secundario asociado con cualquier cláusula de inicializador que lo sigue en la lista separada por comas de la lista de inicializadores ".
Por lo tanto, lo que sucede es:
-
++i
evalúa, obteniendoi = 1
(primer argumento del constructor deS
); -
++i
evalúa, obteniendoi = 2
(segundo argumento del constructor deS
); - El constructor de
S
se ejecuta; - El operador de conversión de
S
se ejecuta, devolviendo el valor2
; - el valor
2
se asigna ai
(que ya tenía el valor2
).
Otro párrafo relevante de la Norma es el § 1.9 / 15, que también menciona ejemplos similares que sí tienen un comportamiento indefinido:
i = v[i++]; // the behavior is undefined
i = i++ + 1; // the behavior is undefined
Sin embargo, el mismo párrafo dice:
" Excepto donde se indique, las evaluaciones de operandos de operadores individuales y de subexpresiones de expresiones individuales no se realizan. [...] Al llamar a una función (independientemente de si la función está en línea), cada valor de cómputo y efecto secundario asociado con cualquier expresión de argumento , o con la expresión de postfijo que designa la función llamada, se secuencia antes de la ejecución de cada expresión o declaración en el cuerpo de la función llamada " .
Desde 1) la evaluación de las expresiones en la lista de inicializadores se secuencia de izquierda a derecha, 2) la ejecución del constructor de S
se secuencia después de la evaluación de todas las expresiones en la lista de inicializadores, y 3) la asignación a i
es secuenciado después de la ejecución del constructor de S
(y su operador de conversión), el comportamiento está bien definido.
Tengo curiosidad sobre las listas de inicializadores y los puntos de secuencia. Hace un tiempo leí que el orden de evaluación en las listas de inicializadores es de izquierda a derecha. Si eso es así, entonces debe haber algún tipo de punto de secuencia entre los puntos de evaluación, ¿estoy equivocado? ¿Entonces con eso dicho es el siguiente código válido? ¿Hay algo que cause un comportamiento indefinido?
int i = 0;
struct S {
S(...) {}
operator int() { return i; }
};
int main() {
i = S{++i, ++i};
}
Cualquiera y todas las respuestas son apreciadas.
Sí, de hecho tiene un caso de comportamiento indefinido.
A continuación hay ejemplos de situaciones que causan un comportamiento indefinido:
- Una variable se cambia varias veces dentro de un punto de secuencia . Como un ejemplo canónico, la expresión i = i ++ a menudo se cita cuando la asignación de la variable iy su incremento se realizan al mismo tiempo. Para obtener más información sobre este tipo de errores, lea la sección "puntos de secuencia" .
- Usar una variable antes de inicializarla Comportamiento indefinido ocurre cuando se trata de usar la variable.
- Asignación de memoria utilizando el nuevo operador [] y su posterior liberación utilizando el operador delete. Por ejemplo: T * p = new T [10]; eliminar p ;. El código correcto es: T * p = new T [10]; eliminar [] p ;.
EDITADO
También su código S {++ i, ++ i}; no está compilado para VS2012. Puede ser que te refieres a S (++ i, ++ i) ;? Si usa "()", entonces el comportamiento indefinido está presente. En otro caso, su código fuente es incorrecto.