Acho que esta parte do projeto de norma em relação à ordem de avaliação é relevante:
1.9 Execução do Programa
...
- Exceto onde indicado, as avaliações de operandos de operadores individuais e de subexpressões de expressões individuais não são sequenciadas. Os cálculos do valor dos operandos de um operador são sequenciados antes do cálculo do valor do resultado do operador. Se um efeito colateral em um objeto escalar não for sequenciado em relação a outro efeito colateral no mesmo objeto escalar ou um cálculo de valor usando o valor do mesmo objeto escalar, e eles não forem potencialmente simultâneos, o comportamento é indefinido
e também:
5.2.2 Chamada de função
...
- [Nota: As avaliações da expressão pós-fixada e dos argumentos são todas sem seqüência em relação umas às outras. Todos os efeitos colaterais das avaliações de argumento são sequenciados antes que a função seja inserida - nota final]
Portanto, para sua linha c.meth1(&nu).meth2(nu);, considere o que está acontecendo no operador em termos do operador de chamada de função para a chamada final para meth2, para que possamos ver claramente a divisão na expressão pós-fixada e no argumento nu:
operator()(c.meth1(&nu).meth2, nu);
As avaliações da expressão pós-fixada e do argumento para a chamada de função final (ou seja, a expressão pós-fixada c.meth1(&nu).meth2e nu) não são sequenciadas entre si de acordo com a regra de chamada de função acima. Portanto, o efeito colateral do cálculo da expressão pós-fixada no objeto escalar não aré sequenciado em relação à avaliação do argumento nuanterior à meth2chamada da função. Pela regra de execução do programa acima, este é um comportamento indefinido.
Em outras palavras, não há nenhum requisito para o compilador avaliar o nuargumento da meth2chamada após a meth1chamada - ele é livre para assumir que nenhum efeito colateral meth1afeta a nuavaliação.
O código de montagem produzido acima contém a seguinte sequência na mainfunção:
- A variável
nué alocada na pilha e inicializada com 0.
- Um cadastro (
ebxno meu caso) recebe uma cópia do valor denu
- Os endereços de
nue csão carregados nos registros de parâmetros
meth1 é chamado
- O registo valor de retorno eo valor previamente armazenado em cache de
nuno ebxregisto são carregados em registradores de parâmetros
meth2 é chamado
De forma crítica, na etapa 5 acima, o compilador permite que o valor em cache da nuetapa 2 seja reutilizado na chamada de função para meth2. Aqui, ele desconsidera a possibilidade de que nupode ter sido alterado pela chamada para meth1- 'comportamento indefinido' em ação.
NOTA: Esta resposta mudou substancialmente de sua forma original. Minha explicação inicial em termos de efeitos colaterais do cálculo do operando não sendo sequenciado antes da chamada da função final estava incorreta, porque eles estão. O problema é o fato de que o cálculo dos próprios operandos é sequenciado de forma indeterminada.