4

Is the destruction of automatic objects (objects created on the stack) guaranteed to be executed not before they go out of scope?

To clarify:

#include <iostream>

class A {
  public:
    A() {
      std::cout << "1";
    }
    ~A() {
      std::cout << "3";
    }
};

void test123() {
  A a;
  std::cout << "2";
}

To print "2", a is not required any more, so theoretically the compiler could try to optimise and destroy a as soon as it is not needed any more.

Can I rely on the above function always printing 123?

bitmask
  • 32,434
  • 14
  • 99
  • 159
  • 1
    I get the sense from this question that you are coming from a garbage collected background. In .NET, for example, this behaviour is _not_ guaranteed; the GC is free to finalize `a` any time after its last reference, which in this case would be the very next line. However, in C++, as those below have mentioned, it is strictly defined. – Mike Caron Aug 28 '11 at 20:41
  • You guessed completely wrong :) --- I am simply using this to implement a recurring pattern of a module. – bitmask Aug 28 '11 at 20:43
  • Oh well, it was worth a shot :) – Mike Caron Aug 28 '11 at 20:44

3 Answers3

10

The destruction order of stack objects is strictly defined - they execute in reverse order of declaration, when you leave the scope (either by running off the end of the {}, or by return, or by an exception). So, you will always see 123 there.

Note, however, that compiler optimizations are governed by the 'as-if' rule. In other words, a compiler can destroy an object early, as long as the resulting program behaves 'as-if' it had been destroyed at the normal time. In this case, because you do output, the compiler must schedule the output at the proper time. However, if you had, for example, deleted a pointer to a primitive type, and the compiler can prove there are no other outstanding pointers to that value, it could, in principle, move that delete earlier. The key is that no conforming program is capable of noticing this optimization.

bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • That sounds good. In the actual case there is not just a `std::cout` but heavy side effects -- a lot of function calls and data-structure modifications before destroying the object. Everything would break if the compiler were to destroy the object first, even if it not used anywhere in the function. So, according to your explanation I'm on the safe side, right? – bitmask Aug 28 '11 at 20:41
  • 1
    @bitmask, yes, the compiler will execute the destructor in a way that it is, effectively, run at the end of the scope. Doing cleanup side-effects in a destructor is considered good style (often referred to as RAII style) – bdonlan Aug 28 '11 at 20:44
  • 1
    Thanks for the confirmation :) – bitmask Aug 28 '11 at 20:55
4

The standard determines that the correct behavior for that code is printing "123". Compilers are allowed to change the code as much as they want while maintaining the same semantics (as-if rule), and reordering of the code here would change the semantics, so a compliant compiler is not allowed to do it.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
0

The constructors may have side effects. For example they might implement a mutex i.e. The constructor locks and the desctuctor unlocks a mutex. Therefore the 123 is required.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127