Я думаю, що ця частина проекту стандарту щодо порядку оцінки є актуальною:
1.9 Виконання програми
...
- За винятком випадків, коли оцінки операндів окремих операторів та підвиразів окремих виразів не є наслідком. Обчислення значень операндів оператора секвенуються перед обчисленням значення результату оператора. Якщо побічний ефект на скалярний об'єкт не є наслідком щодо іншого побічного ефекту на той самий скалярний об'єкт або обчислення значення, використовуючи значення того ж скалярного об'єкта, і вони потенційно не є одночасним, поведінка не визначена
і також:
5.2.2 Виклик функції
...
- [Примітка: Оцінки експресії постфіксу та аргументів не мають наслідків один щодо одного. Всі побічні ефекти оцінок аргументів простежуються перед введенням функції - кінцева примітка]
Отже, для вашої лінії c.meth1(&nu).meth2(nu);
розгляньте, що відбувається в операторі з точки зору оператора виклику функції для остаточного виклику meth2
, щоб ми чітко бачили розбиття на вираз та аргумент постфіксу nu
:
operator()(c.meth1(&nu).meth2, nu);
В оцінках вираження постфікса і аргумент для виклику функції кінцевого (тобто вираз постфікса c.meth1(&nu).meth2
і nu
) є unsequenced відносно один одного відповідно до викликом функції правило , вище. Отже, побічний ефект обчислення виразу постфіксу на скалярному об'єкті не ar
є наслідком щодо оцінки аргументу nu
до meth2
виклику функції. За правилом виконання програми вище, це невизначена поведінка.
Іншими словами, для компілятора немає вимоги оцінювати nu
аргумент до meth2
виклику після meth1
виклику - вільний припускати, що жодні побічні ефекти не meth1
впливають на nu
оцінку.
Код складання, вироблений вище, містить таку послідовність у main
функції:
- Змінна
nu
виділяється на стек і ініціалізується з 0.
- Реєстр (
ebx
у моєму випадку) отримує копію значенняnu
- Адреси
nu
та c
завантажуються в регістри параметрів
meth1
це називається
- Регістр значення, що повертається , і раніше кешований значення з
nu
в ebx
регістрі завантажуються в регістри параметрів
meth2
це називається
Критично, на етапі 5 вище компілятор дозволяє nu
повторно використовувати кешоване значення з кроку 2 у виклику функції до meth2
. Тут він нехтує можливістю, яка, nu
можливо, була змінена закликом до meth1
«невизначеної поведінки» в дії.
ПРИМІТКА. Ця відповідь змінилася по суті від її початкової форми. Моє початкове пояснення щодо побічних ефектів обчислення операндів, які не були секвенсовані перед кінцевим викликом функції, були невірними, оскільки вони є. Проблема полягає в тому, що обчислення самих операндів невизначено послідовно.