There is a special rule about an atomatic variable of a type with constructors or destructors with side effects, such as this code's a
: such a variable cannot be optimized away even if it's apparently unused.
In C++14 (I'm using the N3936 draft) this is
C++14 §3.7.3/3 (basic.stc.auto/3):
” If a variable with automatic storage duration has initialization or a destructor with side effects, it shall not
be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8.
The wording was the same in C++03.
Well, the nice thing about the standard is that it's often not quite 100% clear-cut, leaving room for discussions! Here we can read “(initialization or a destructor) with side effects”, or “initialization or (a destructor with side effects)”. Thinking about what's reasonable it's clearly the first interpretation that is the intended meaning.
Re
” Is it guaranteed that it will print Foo\nBar\n
, in that order?
Yes.
The optimizations in C++ are constrained to yield the same visible effect as your source code's direct meaning, which is called the “as-if” rule.
C++14 §1.9/1 (intro.execution/1):
” The semantic descriptions in this International Standard define a parameterized nondeterministic abstract
machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.
The following paragraphs detail what that means, e.g. that all bets are off with Undefined Behavior in the picture.
At the end of the above paragraph there is this non-normative footnote:
” This provision is sometimes called the “as-if” rule, because an implementation is free to disregard any requirement of this International Standard as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program. For instance, an actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no side effects affecting the observable behavior of the program are produced.
Then, safe from optimizations, no UB here!, only the defined effects of the source need to be considered.
And these defined effects are, as noted in Igor's answer, produced by two full-expressions, where the standard guarantees that all effects of the first one will be complete before the second one is executed.
In other news:
The return 0;
in main
is not needed, because that's the default for main
.
The program is formally not portable, because <cstdio>
is not guaranteed to place printf
in the global namespace. Include <stdio.h>
instead. This is not the C header of the same name: it's a C++ header that has the same effect as <cstdio>
except for which namespaces are guaranteed to be used.