yeputons
yeputons

Reputation: 9238

Is it guaranteed that constructor is called exactly when the variable is defined?

Consider the following code:

#include <cstdio>

struct A {
  A() {
    printf("Bar\n");
  }
};

int main() {
  printf("Foo\n");
  A a;
  return 0;
}

Is it guaranteed that it will print Foo\nBar\n, in that order? My experience says "yes", but I want to have some quote from C++11 standard or MSDN reference to point to, because somebody told me that it's possible for compiler to call constructor before the actual line of declaration.

It would be more obvious if the constructor had some arguments (because they can depend on values which are not computed when function starts), and less obvious if there was default constructor only. Say, JavaScript is famous for making variables defined before the var line available:

function main() {
  console.log(x);
  var x = 2;
  console.log(y);
}
main();

The code above will print undefined as value of x and then fail with y is not defined.

Upvotes: 2

Views: 185

Answers (5)

Ethouris
Ethouris

Reputation: 1901

In short: There may be rules that allow compiler to elide construction or simply "do things that won't have any observable difference" - but well, what useful for you is the knowledge about things that you can't observe anyway?

The only situation when it can make any difference are the global variables, but it's a little bit different story - the global variables don't have defined order of initialization. Variables that are local to the function are always "runtime variables", which means that they physically don't exist prior to declaration. Moreover, you can use variables declared earlier in the arguments for initialization of variables declared later - so the initialization order must be ensured at least in this case.

May happen that a compiler can do stack allocation for all variables at once, then fill in all of them as needed. However local variables will be runtime-initialized anyway. I can imagine that you may observe something like reordered initialization in this situation:

int a = 0, b = 0;
A ax;
int c = 0, d = 0;

May happen that a compiler can decide to allocate a single stack frame for all these variables and clear the whole memory area under them - I doubt any compiler does, but at least there's nothing wrong with doing that. In this case you might observe that c contains zero before A::A() is called.

This can be done because the assignment of 0 to c is runtime-independent, so it could be done earlier than it seems to be. However, this variable theoretically shouldn't exist before A::A() is called, so what is really cleared from the language point of view is some stack memory not yet assigned to variable's symbols.

If you ask for any observable side effect - yes, it is guaranteed that all observable results (not only side effects) of local variable initialization are exactly such as when the variables are being constructed exactly in the order in which they were declared (moreover, they are being "destructed" in the reverse order).

Upvotes: 0

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

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.

Upvotes: 1

user1084944
user1084944

Reputation:

You are guaranteed that this program will output Foo\nBar\n.

However, that's all you're guaranteed. That's the behavior your program will display, but by the as-if rule, you aren't guaranteed anything about how that behavior is accomplished. You have no guarantees about when the constructor gets called, or even if the constructor gets called. Your program's executable code might not even have a constructor in it at all! You're not even guaranteed that the variable a exists somewhere in the program.

And that's not theoretical; if your compiler is worth anything at all, with optimizations turned on your program should compile to exactly the same thing as does the program

#include <cstdio>
int main() {
    std::printf("Foo\n");
    std::printf("Bar\n");
    return 0;
}

Upvotes: 5

Igor Tandetnik
Igor Tandetnik

Reputation: 52471

[intro.execution]/10 A full-expression is an expression that is not a subexpression of another expression. [ Note: in some contexts, such as unevaluated operands, a syntactic subexpression is considered a full-expression (Clause 5). —end note ] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition.

.

[intro.execution]/14 Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

Upvotes: 7

R Sahu
R Sahu

Reputation: 206607

because somebody told me that it's possible for compiler to call constructor before the actual line of declaration.

The compiler has the freedom to do that only if it can prove that the observable behavior of the program will not change by doing that. In your case, that is not true. Hence, a conforming compiler will not call the constructor before the line of declaration.

Upvotes: 6

Related Questions