El resultado de este programa:
#include <iostream>
class c1
{
public:
c1& meth1(int* ar) {
std::cout << "method 1" << std::endl;
*ar = 1;
return *this;
}
void meth2(int ar)
{
std::cout << "method 2:"<< ar << std::endl;
}
};
int main()
{
c1 c;
int nu = 0;
c.meth1(&nu).meth2(nu);
}
Es:
method 1
method 2:0
¿Por qué nuno es 1 cuando meth2()comienza?
c++
chaining
operator-precedence
Moises Viñas
fuente
fuente

nu,&nuycen la pila en ese orden, luego invocarmeth1, empujar el resultado a la pila, luego invocarmeth2, mientras que una convención de llamadas basada en registros querría cargarcy&nuen registros, invocarmeth1, cargarnuen un registro, luego invocarmeth2.Respuestas:
Porque el orden de evaluación no está especificado.
Estás viendo
nuenmainser evaluado0antes incluso demeth1ser llamado. Este es el problema del encadenamiento. Aconsejo no hacerlo.Simplemente cree un programa agradable, simple, claro, fácil de leer y de entender:
fuente
<<para la salida y "constructores de objetos" para objetos complejos con demasiados argumentos para los constructores, pero se mezcla muy mal con los argumentos de salida.meth1ymeth2está definido, pero la evaluación del parámetro parameth2puede ocurrir antes de quemeth1se llame ...?meth2(meth1(c, &nu), nu)Creo que esta parte del borrador del estándar con respecto al orden de evaluación es relevante:
y también:
Entonces, para su línea
c.meth1(&nu).meth2(nu);, considere lo que está sucediendo en el operador en términos del operador de llamada de función para la llamada final ameth2, de modo que veamos claramente el desglose en la expresión y el argumento de sufijonu:Las evaluaciones de la expresión de sufijo y el argumento para la llamada de función final (es decir, la expresión de sufijo
c.meth1(&nu).meth2ynu) no están secuenciadas entre sí según la regla de llamada de función anterior. Por lo tanto, el efecto secundario del cálculo de la expresión de sufijo en el objeto escalar noarestá secuenciado en relación con la evaluación del argumentonuantes de lameth2llamada a la función. Según la regla de ejecución del programa anterior, este es un comportamiento indefinido.En otras palabras, no es necesario que el compilador evalúe el
nuargumento de lameth2llamada después de lameth1llamada; es libre de asumir que no hay efectos secundarios quemeth1afecten lanuevaluación.El código ensamblador producido por lo anterior contiene la siguiente secuencia en la
mainfunción:nuse asigna en la pila y se inicializa con 0.ebxen mi caso) recibe una copia del valor denunuycse cargan en registros de parámetrosmeth1se llamanuen elebxregistro se cargan en los registros de parámetrosmeth2se llamaCríticamente, en el paso 5 anterior, el compilador permite que el valor en caché
nudel paso 2 se reutilice en la llamada de función ameth2. Aquí se ignora la posibilidad de quenupueda haber sido cambiado por la llamada ameth1- 'comportamiento indefinido' en acción.NOTA: Esta respuesta ha cambiado sustancialmente desde su forma original. Mi explicación inicial en términos de los efectos secundarios del cálculo de operandos que no se secuenciaron antes de la llamada final a la función fue incorrecta, porque lo son. El problema es el hecho de que el cálculo de los propios operandos tiene una secuencia indeterminada.
fuente
meth1se ejecuta antesmeth2, pero el parámetro parameth2es un valor denucaché en un registro antes de la llamada ameth1, es decir, el compilador ha ignorado los posibles efectos secundarios, que es coherente con mi respuesta.c.meth1(&nu).meth2) y la evaluación del argumento de esa llamada (nu) generalmente no tienen secuencia, pero 1) sus efectos secundarios están todos secuenciados antes de la entradameth2y 2) ya quec.meth1(&nu)es una llamada de función , tiene una secuencia indeterminada con la evaluación denu. En el interiormeth2, si de alguna manera obtiene un puntero a la variable enmain, siempre verá 1.meth2, como se indica en el elemento 3 de la página de referencia de cpp que está citando (que también se olvidó de citar correctamente).En el estándar C ++ de 1998, Sección 5, párrafo 4
(He omitido una referencia a la nota al pie # 53 que no es relevante para esta pregunta).
Esencialmente,
&nudebe evaluarse antes de llamarc1::meth1()ynudebe evaluarse antes de llamarc1::meth2(). Sin embargo, no hay ningún requisito quenudeba evaluarse antes&nu(por ejemplo, se permite quenuse evalúe primero, luego&nu, y luegoc1::meth1()se llame, que podría ser lo que está haciendo su compilador). Por lo tanto, no se garantiza que la expresión*ar = 1inc1::meth1()se evalúe antesnude quemain()se evalúe in para poder pasarla ac1::meth2().Los estándares posteriores de C ++ (que actualmente no tengo en la PC que estoy usando esta noche) tienen esencialmente la misma cláusula.
fuente
Creo que al compilar, antes de que las funciones meth1 y meth2 se llamen realmente, se les han pasado los parámetros. Me refiero a cuando usa "c.meth1 (& nu) .meth2 (nu);" el valor nu = 0 se ha pasado a meth2, por lo que no importa si "nu" se cambia más tarde.
puedes probar esto:
obtendrá la respuesta que desea
fuente