Search code examples
c++destructortemporaryobject-lifetime

What is the order of calling destructors for temporaries in C++?


Consider the following code:

#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();
}

Compiling with GCC and running gives the following output:

~C
~A
~B

Is it guaranteed that the destructors for temporary objects of types A, B and C will be called in this order when compiled with other compilers? In general, what is the order of destructor calls for temporaries if there is any?


Solution

  • Let's talk about subexpressions and their sequencing. If E1 is sequenced before E2, that means E1 must be fully evaluated before E2 is. If E1 is unsequenced with E2, that means E1 and E2 may be evaluated in any order.

    For f(A()) << B(), which is in your case the same as f(A()).operator<<(B()), we know that:

    • A() is sequenced before f(...),
    • f(...) is sequenced before operator<< and
    • B() is sequenced before operator<<

    This also tells us that:

    • A() is sequenced before operator<<
    • A() is unsequenced with B()
    • f(...) is unsequenced with B()

    If we assume RVO, so as not to complicate things, the possible order a compiler could evaluate the subexpressions in are:

    • A() -> f(...) -> B(), yielding ~B() -> ~C() -> ~A()
    • A() -> B() -> f(...), yielding ~C() -> ~B() -> ~A()
    • B() -> A() -> f(...), yielding ~C() -> ~A() -> ~B()

    The latter is the order observed in the OP. Note that the order of destruction is always the reverse order of construction.