sirve significa que para namespace libreria leer dev declarar como cint c++ c++-faq

c++ - significa - ¿Cuál es la respuesta correcta para cout<< a++<< a;?



que significa endl en c++ (4)

Recientemente en una entrevista hubo una siguiente pregunta de tipo objetivo.

int a = 0; cout << a++ << a;

Respuestas

a. 10
segundo. 01
do. comportamiento indefinido

Respondí la opción b, es decir, la salida sería "01".

Pero para mi sorpresa más tarde, un entrevistador me dijo que la respuesta correcta es la opción c: indefinida.

Ahora, sé el concepto de puntos de secuencia en C ++. El comportamiento no está definido para la siguiente declaración:

int i = 0; i += i++ + i++;

pero según mi comprensión para la declaración cout << a++ << a , el ostream.operator<<() se llamaría dos veces, primero con ostream.operator<<(a++) y más tarde ostream.operator<<(a) .

También verifiqué el resultado en el compilador VS2010 y su salida también es ''01''.


La respuesta correcta es cuestionar la pregunta. La declaración es inaceptable porque un lector no puede ver una respuesta clara. Otra forma de verlo es que hemos introducido los efectos secundarios (c ++) que hacen que la afirmación sea mucho más difícil de interpretar. El código conciso es excelente, siempre que su significado sea claro.


Los puntos de secuencia solo definen un orden parcial . En su caso, tiene (una vez que se realiza la resolución de sobrecarga):

std::cout.operator<<( a++ ).operator<<( a );

Hay un punto de secuencia entre a++ y la primera llamada a std::ostream::operator<< , y hay un punto de secuencia entre la segunda a y la segunda llamada a std::ostream::operator<< , pero allí no hay punto de secuencia entre a++ y a ; las únicas restricciones de ordenamiento son que a++ se evalúe por completo (incluidos los efectos secundarios) antes de la primera llamada al operator<< , y que el segundo a se evalúe por completo antes de la segunda llamada al operator<< . (También existen restricciones causales de ordenación: la segunda llamada al operator<< no puede preceder a la primera, ya que requiere los resultados del primero como argumento.) §5 / 4 (C ++ 03) establece:

Excepto cuando se indique lo contrario, el orden de evaluación de operandos de operadores individuales y las subexpresiones de expresiones individuales, y el orden en que se producen los efectos secundarios, no se especifica. Entre el punto de secuencia anterior y siguiente, un objeto escalar tendrá su valor almacenado modificado como máximo una vez por la evaluación de una expresión. Además, se accederá al valor anterior solo para determinar el valor que se almacenará. Los requisitos de este párrafo se cumplirán para cada orden permisible de las subexpresiones de una expresión completa; de lo contrario, el comportamiento no está definido.

Uno de los ordenamientos permitidos de su expresión es a++ , a , primera llamada al operator<< , segunda llamada al operator<< ; esto modifica el valor almacenado de a ( a++ ), y lo accede a otro que no sea para determinar el nuevo valor (el segundo a ), el comportamiento no está definido.


Técnicamente, en general, esto es un comportamiento indefinido .

Pero, hay dos aspectos importantes en la respuesta.

La declaración del código:

std::cout << a++ << a;

se evalúa como:

std::operator<<(std::operator<<(std::cout, a++), a);

El estándar no define el orden de evaluación de argumentos para una función.
Así que O bien:

  • std::operator<<(std::cout, a++) se evalúa primero o
  • a se evalúa primero o
  • puede ser cualquier orden de implementación definida.

Esta orden no se especifica [Ref 1] según el estándar.

[Ref 1] C ++ 03 5.2.2 Llamada de función
Para 8

El orden de evaluación de los argumentos no está especificado . Todos los efectos secundarios de las evaluaciones de expresión de argumentos surten efecto antes de que se ingrese la función. El orden de evaluación de la expresión de postfijo y la lista de expresión de argumento no está especificado.

Además, no existe un punto de secuencia entre la evaluación de los argumentos para una función, pero existe un punto de secuencia solo después de la evaluación de todos los argumentos [Ref 2] .

[Ref 2] C ++ 03 1.9 Ejecución del programa [intro.execution]:
Párrafo 17:

Cuando se llama a una función (ya sea que la función esté o no en línea), hay un punto de secuencia después de la evaluación de todos los argumentos de funciones (si los hay) que tienen lugar antes de la ejecución de cualquier expresión o declaración en el cuerpo de la función.

Tenga en cuenta que, aquí el valor de c se accede más de una vez sin un punto de secuencia intermedio, con respecto a esto, el estándar dice:

[Ref 3] C ++ 03 5 Expresiones [expr]:
Para 4:

....
Entre el punto de secuencia anterior y siguiente, un objeto escalar tendrá su valor almacenado modificado como máximo una vez por la evaluación de una expresión. Además, se accederá al valor anterior solo para determinar el valor que se almacenará . Los requisitos de este párrafo se cumplirán para cada orden permisible de las subexpresiones de una expresión completa; de lo contrario, el comportamiento no está definido .

El código modifica c más de una vez sin un punto de secuencia intermedio y no se está accediendo para determinar el valor del objeto almacenado. Esto es una clara violación de la cláusula anterior y, por lo tanto, el resultado según lo ordenado por la norma es el Comportamiento Indefinido [Ref 3] .


Tu puedes pensar en:

cout << a++ << a;

Como:

std::operator<<(std::operator<<(std::cout, a++), a);

C ++ garantiza que todos los efectos secundarios de las evaluaciones previas se habrán realizado en puntos de secuencia . No hay puntos de secuencia entre la evaluación de argumentos de función, lo que significa que el argumento a se puede evaluar antes del argumento std::operator<<(std::cout, a++) o posterior. Por lo tanto, el resultado de lo anterior no está definido.

Actualización C ++ 17

En C ++ 17, las reglas se han actualizado. En particular:

En una expresión de operador de desplazamiento E1<<E2 y E1>>E2 , cada cómputo de valor y efecto secundario de E1 se secuencia antes de cada cálculo de valor y efecto secundario de E2 .

Lo que significa que requiere que el código produzca el resultado b , que produce 01 .

Ver P0145R3 Refining Expression Evaluation Order para Idiomatic C ++ para más detalles.