Considere este tema como una secuela del siguiente tema:
Entrega anterior
Comportamiento indefinido y puntos de secuencia
Repasemos esta expresión divertida y complicada (las frases en cursiva se tomaron del tema anterior * sonrisa *):
i += ++i;
Decimos que esto invoca un comportamiento indefinido. Supongo que cuando digo esto, asumimos implícitamente que el tipo de ies uno de los tipos integrados.
¿Qué pasa si el tipo de ies un tipo definido por el usuario? Digamos que su tipo es el Indexque se define más adelante en esta publicación (ver más abajo). ¿Seguiría invocando un comportamiento indefinido?
¿Si es así por qué? ¿No es equivalente a escribir i.operator+=(i.operator++());o incluso sintácticamente más simple i.add(i.inc());? ¿O también invocan un comportamiento indefinido?
Si no, ¿por qué no? Después de todo, el objeto ise modifica dos veces entre puntos de secuencia consecutivos. Recuerde la regla general: una expresión puede modificar el valor de un objeto solo una vez entre "puntos de secuencia consecutivos" . Y si i += ++ies una expresión, debe invocar un comportamiento indefinido. Si es así, sus equivalentes i.operator+=(i.operator++());y i.add(i.inc());también debe invocar un comportamiento indefinido que parece ser falso! (hasta donde yo entiendo)
¿O i += ++ino es una expresión para empezar? Si es así, ¿qué es y cuál es la definición de expresión ?
Si es una expresión y, al mismo tiempo, su comportamiento también está bien definido, entonces implica que el número de puntos de secuencia asociados con una expresión depende de alguna manera del tipo de operandos involucrados en la expresión. ¿Estoy en lo correcto (incluso en parte)?
Por cierto, ¿qué tal esta expresión?
//Consider two cases:
//1. If a is an array of a built-in type
//2. If a is user-defined type which overloads the subscript operator!
a[++i] = i; //Taken from the previous topic. But here type of `i` is Index.
También debe considerar esto en su respuesta (si conoce su comportamiento con seguridad). :-)
Es
++++++i;
bien definido en C ++ 03? Después de todo, esto es esto
((i.operator++()).operator++()).operator++();
class Index
{
int state;
public:
Index(int s) : state(s) {}
Index& operator++()
{
state++;
return *this;
}
Index& operator+=(const Index & index)
{
state+= index.state;
return *this;
}
operator int()
{
return state;
}
Index & add(const Index & index)
{
state += index.state;
return *this;
}
Index & inc()
{
state++;
return *this;
}
};

ses un tipo definido por el usuario!)Respuestas:
Parece el código
i.operator+=(i.operator ++());Funciona perfectamente bien con respecto a los puntos de secuencia. La sección 1.9.17 del estándar ISO C ++ dice esto sobre los puntos de secuencia y la evaluación de funciones:
Esto indicaría, por ejemplo, que
i.operator ++()como parámetrooperator +=tiene un punto de secuencia después de su evaluación. En resumen, dado que los operadores sobrecargados son funciones, se aplican las reglas de secuenciación normales.¡Gran pregunta, por cierto! Me gusta mucho cómo me estás obligando a entender todos los matices de un idioma que ya pensé que conocía (y pensé que pensé que sabía). :-)
fuente
http://www.eelis.net/C++/analogliterals.xhtml Me vienen a la mente literales analógicos
unsigned int c = ( o-----o | ! ! ! ! ! o-----o ).area; assert( c == (I-----I) * (I-------I) ); assert( ( o-----o | ! ! ! ! ! ! ! o-----o ).area == ( o---------o | ! ! ! o---------o ).area );fuente
Como han dicho otros, su
i += ++iejemplo funciona con el tipo definido por el usuario, ya que está llamando a funciones, y las funciones comprenden puntos de secuencia.Por otro lado,
a[++i] = ino es tan afortunado asumir queaes su tipo de matriz básico, o incluso uno definido por el usuario. El problema que tiene aquí es que no sabemos qué parte de la expresión que contieneise evalúa primero. Podría ser que++ise evalúe, se pase aoperator[](o la versión sin procesar) para recuperar el objeto allí, y luego el valor deise pase a ese (que es después de que se incrementó i). Por otro lado, quizás el último lado se evalúe primero, se almacene para una asignación posterior y luego++ise evalúe la parte.fuente
++iy la lectura deien el RHS de la asignación, entonces el orden no estaría especificado. Debido a que uno de los ordenamientos permitidos hace esas dos cosas sin un punto de secuencia intermedio, el comportamiento no está definido.aintegrado y definido por el usuarioi.Creo que está bien definido:
Del borrador del estándar C ++ (n1905) §1.9 / 16:
Tenga en cuenta la parte en negrita. Esto significa que de hecho hay un punto de secuencia después de la llamada de función de incremento (
i.operator ++()) pero antes de la llamada de asignación compuesta (i.operator+=).fuente
Bien. Después de repasar las respuestas anteriores, volví a pensar en mi propia pregunta, particularmente en esta parte que solo Noah intentó responder, pero no estoy completamente convencido con él.
Caso 1:
Si
aes una matriz de tipo incorporado. Entonces lo que dijo Noah es correcto. Es decir,Entonces
a[++i]=iinvoca un comportamiento indefinido, o el resultado no está especificado. Sea lo que sea, ¡no está bien definido!PD: en la cita anterior,
tachadoes por supuesto mío.Caso 2:
Si
aes un objeto de tipo definido por el usuario que sobrecarga eloperator[], entonces nuevamente hay dos casos.operator[]función sobrecargada es un tipo integrado, de nuevoa[++i]=iinvoca un comportamiento indefinido o el resultado no está especificado.operator[]función sobrecargada es un tipo definido por el usuario, entonces el comportamiento dea[++i] = iestá bien definido (hasta donde tengo entendido), ya que en este casoa[++i]=ies equivalente a escribira.operator[](++i).operator=(i);que es lo mismo quea[++i].operator=(i);,. Es decir, la asignaciónoperator=se invoca en el objeto devuelto dea[++i], que parece estar muy bien definido, ya que para el momento en que losa[++i]retornos++iya se han evaluado, y luego el objeto devuelto llama a laoperator=función y le pasa el valor actualizado deicomo argumento. Tenga en cuenta que hay un punto de secuencia entre estas dos llamadas . Y la sintaxis asegura que no haya competencia entre estas dos llamadas, yoperator[]se invocaría primero, y consecutivamente, el argumento que se le++ipasó, también se evaluaría primero.Piense en esto como
someInstance.Fun(++k).Gun(10).Sun(k).Tun();en el que cada llamada de función consecutiva devuelve un objeto de algún tipo definido por el usuario. Para mí, esta situación se parece más a esto:,eat(++k);drink(10);sleep(k)porque en ambas situaciones, existe un punto de secuencia después de cada llamada de función.Por favor corrígeme si estoy equivocado. :-)
fuente
k++y nokestán separados por puntos de secuencia. Ambos pueden ser evaluados antes de o son evaluados. El lenguaje solo requiere que se evalúe antes , no que los argumentos se evalúen antes que los argumentos. Estoy volviendo a explicar lo mismo sin poder dar una referencia, así que no vamos a progresar desde aquí.SunFunFunSunFunSunSunejecución, peroFunel argumento++kpuede evaluarse antes o después de eso. Hay puntos de secuencia antes y después de laFunejecución, peroSunel argumentokpuede evaluarse antes o después de eso. Por lo tanto, un caso posible es que ambosky++kse evalúan antes queSunoFunse evalúan, por lo que ambos están antes de los puntos de secuencia de llamada de función, por lo que no hay un punto de secuencia que separeky++k.eat(i++);drink(10);sleep(i);? ... incluso ahora, ¿podría decirse quei++puede ser evaluado antes o después de eso?ky++k. En el ejemplo de comer / beber, no es como punto de secuencia entreiyi++.eat()ysleep()existe punto (s) de secuencia, pero entre hay argumentos ni siquiera uno. ¿Cómo pueden los argumentos de dos llamadas a funciones separadas por puntos de secuencia pertenecer a los mismos puntos de secuencia?