Рассмотрим следующий код:
#include <iostream>
struct A {
~A() { std::cout << "~A" << std::endl; }
};
struct B {
~B() { std::cout << "~B" << std::endl; }
};
struct C {
~C() { std::cout << "~C" << std::endl; }
void operator<<(const B &) {}
};
C f(const A &a = A()) {
return C();
}
int main() {
f(A()) << B();
}
Компиляция с GCC и выполнение дает следующий вывод:
~C
~A
~B
Гарантируется ли, что деструкторы для временных объектов типов A, B и C будут вызываться в этом порядке при компиляции с другими компиляторами? В общем, каков порядок вызовов деструкторов для временных, если они есть?
Давайте поговорим о подвыражениях и их последовательности. Если E1
является последовательность перед E2
, это означает E1
должны быть полностью оценены до E2
является. Если E1
является без последовательности с E2
, это означает E1
а также E2
может оцениваться в любом порядке.
За f(A()) << B()
, который в вашем случае так же, как f(A()).operator<<(B())
, мы знаем это:
A()
последовательность перед f(...)
,f(...)
последовательность перед operator<<
а такжеB()
последовательность перед operator<<
Это также говорит нам о том, что:
A()
последовательность перед operator<<
A()
не секвенируется с B()
f(...)
не секвенируется с B()
Если мы предполагаем RVO, чтобы не усложнять ситуацию, возможный порядок, в котором компилятор может оценивать подвыражения в:
A()
-> f(...)
-> B()
, уступая ~B()
-> ~C()
-> ~A()
A()
-> B()
-> f(...)
, уступая ~C()
-> ~B()
-> ~A()
B()
-> A()
-> f(...)
, уступая ~C()
-> ~A()
-> ~B()
Последний порядок наблюдается в ОП. Обратите внимание, что порядок уничтожения всегда является обратным порядком построения.
Порядок оценки выражения f(A()) << B();
не указано Таким образом, порядок строительства / уничтожения также не указан.
Порядок оценки операндов <<
не указано Следовательно, порядок не гарантируется. Только операторы короткого замыкания &&
, ||
троичный оператор ?:
и запятая ,
Оператор имеет четко определенный порядок вычисления операндов. Для других нет необходимости, чтобы левый операнд оценивался перед правым операндом (или наоборот).
Кроме того, не путайте приоритет оператора или ассоциативность с порядком вычисления. Для данного выражения E1 op E2
Надо только, чтобы перед оператором op
применяется как E1
а также E2
следует оценить, но между собой, E1
а также E2
можно оценить в любом порядке.
Правила приоритета определяют порядок, в котором применяются операторы, когда в выражении более одного оператора, например E1 op1 E2 op2 E3
,
Ассоциативность используется для определения того, какие операнды связываются с каким оператором, когда один и тот же оператор используется более одного раза, то есть в E1 op E2 op E3
интерпретируется ли это как (E1 op E2) op E3
или же E1 op (E2 op E3)
,