tipos programacion operadores logicos expresiones asignacion aritmeticos c++ c sequence-points

c++ - programacion - ¿Alguna buena razón por la que el operador de asignación no es un punto de secuencia?



operadores y expresiones en c++ (3)

Es (tipo de). El operador = (que puede ser definido por el ingeniero (también conocido como el operador definido por el usuario = para los tipos de clase)) es solo azúcar sintáctica para una llamada de función. Como resultado, tiene la misma semántica de "punto de secuencia" que una llamada de función.

Si estamos tomando sobre tipos integrados, entonces creo que es algo bueno.
No desea introducir demasiados puntos de secuencia, ya que esto dificulta las optimizaciones.

¿Hay alguna buena razón para que el operator = no sea un punto de secuencia? Tanto en C como en C ++.

Tengo problemas para pensar en un contra-ejemplo.


Hay muchas razones para no requerir que una de las partes sea evaluada antes que la otra. Una pregunta más interesante es si la evaluación de ambos lados, completa con efectos secundarios, debe ser requerida antes de que el operador de la asignación haga algo. Sugeriría que tal requisito facilitaría algunas restricciones de aliasing pero en algunos casos requiere más trabajo para un compilador. Por ejemplo, supongamos que "foo" y "barra" son punteros a estructuras grandes cuyas direcciones se superpondrían. La declaración "* foo = * bar;" representaría un comportamiento indefinido bajo la norma actual. Si hubiera un punto de secuencia entre la evaluación de los operandos y la asignación, se garantizaría que dicha declaración "funcionara". Tal garantía requeriría más complicada para el operador de asignación, requiriendo un código más grande y más lento incluso si en la práctica los punteros nunca se superpondrán.

Ejemplo:

unsigned char foo[100]; typedef struct {int x, int y;} POINT; POINT *p1 = (POINT*)foo; POINT *p2 = (POINT*)(&(p1->y));

Dadas las declaraciones anteriores, creo que las siguientes declaraciones tienen los comportamientos estrictamente definidos indicados y no implican ningún comportamiento indefinido.

p1->y = somevalue; // Sets p2->x to somevalue p2->x = somevalue; // Sets p1->y to somevalue *p1 = mystruct; // Sets p2->x to mystruct.y *p2 = mystruct; // Sets p1->x to mystruct.x

Las siguientes dos afirmaciones, sin embargo, involucrarían un comportamiento indefinido:

*p1 = *p2; *p2 = *p1;

Si hubiera un punto de secuencia en el signo igual, un compilador tendría que comparar p1 y p2, o bien copiar el operando de origen en una ubicación temporal y luego copiarlo en el destino. Sin embargo, el estándar deja claro que las dos afirmaciones anteriores se consideran como comportamiento indefinido. El estándar requiere que los compiladores generen un código que funcione correctamente cuando se copia una estructura a una estructura no superpuesta, pero no impone restricciones sobre lo que pueden hacer los compiladores si las estructuras se superponen. Un compilador que haría el procesador en un bucle enviando "Reglas de Frink!" cada socket TCP abierto no violaría el estándar al hacerlo.


Por solicitud:

En general, las cosas necesitan una razón para ser un punto de secuencia. No necesitan una razón para no ser un punto de secuencia; ese es el predeterminado

Por ejemplo, && debe ser un punto de secuencia debido a un comportamiento de cortocircuito: si el lado izquierdo es falso, el lado derecho no debe evaluarse . (Esto no se trata solo de optimización; el lado derecho podría tener efectos secundarios y / o depender de que el lado izquierdo sea verdadero, como en ptr && ptr->data ). Por lo tanto, el lado izquierdo debe ser evaluado Primero, antes del lado derecho, para ver si el lado derecho debe ser evaluado.

Esta razón no existe para = porque, aunque hay una "evaluación" para ambos lados (aunque existen diferentes restricciones sobre lo que puede aparecer en ambos lados: el lado izquierdo debe ser un valor lime, el l no está parado para "izquierda", por cierto, significa "ubicación", como en ubicación en la memoria (no podemos asignar un temporal o un literal), no importa qué lado se evalúe primero, siempre que ambos lados estén Evaluado antes de la asignación real.