1

Let's say I write a class Foo with a constructor Foo(int). And I have this piece of code:

Foo a(i), b = a + Foo(2);

If I call the constructor in the code with a constant, e.g. Foo(2), does the compiler run it once and store the result for run-time, or is it executed at run-time? Is it the same whether or not the struct/class contains only POD data types?

Assuming that it executes at run-time (which I believe to be the case), is there a way to make it run at compile-time, or have the same effects as if it were run as such?

Edit: I'm afraid I didn't make myself clear. I am referring to the Foo(2) part for the code, which is completely immutable. Also, I am unable to utilise C++11 (I am working with GCC 4.1 and cannot upgrade), so constexpr, while valid, is unsuitable for me.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
Alex Koay
  • 2,915
  • 4
  • 18
  • 16
  • Is this at the global scope or in a function? – Kerrek SB May 24 '12 at 05:04
  • I'm considering cases inside a function. I am concerned about having to evaluate `Foo(2)` multiple times. – Alex Koay May 24 '12 at 06:54
  • 1
    Totally depends on compiler and optimization level. It is allowed to (if that is the question). Whether it does will depend on if Foo has side affects, how simple it is and other factors. Why not compile it to assembly and look at it. – Martin York May 24 '12 at 14:18

6 Answers6

3

It's possible to have your a use constant initialization, which is static initialization, but for that to happen:

  1. i most be a constant expression
  2. Foo::Foo(int) must be constexpr
  3. Any/all other functions/ctors used by Foo:Foo(int) must also be constexpr.

The same would be pretty much the case for your b -- Foo(2) would have to be constexpr, and Foo::operator+(Foo const &) or Foo operator+(Foo const &, Foo const &) (whichever you have) would have to be constexpr.

The definition of a constant expression is at §5.19 of the C++11 standard, in case you want to investigate in more detail. My immediate guess is that if Foo is fairly simple, it's probably possible for a, but I'm a lot less certain about b.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
3

Let's say I write a class Foo with a constructor Foo(int). And I have this piece of code:

Foo a(i), b = a + Foo(2);

If I call the constructor in the code with a constant, does the compiler run it once, and store the result for run-time, or is it executed at run-time?

There are two levels to this:

  • is it possible and legal w.r.t. the Standard for a perfect optimiser -- achieving everything an expert person could potentially do with unlimited effort and genius - to do this at compile time, and
  • is compile-time behaviour required / guaranteed by the Standard.

Is i a compile time constant? If not, and the value of i passed to Foo::Foo(i) influence its behaviour (whether affecting data member values or side-effects like logging), then clearly it's inherently impossible to construct Foo(i) at compile time. If i is constant, it may still be inherently impossible - for example the constructor implementation may have behaviour based on the current time, or need to consult some other run-time data. Such problems may also prevent Foo(2) being possible to evaluate at compile-time.

If i is constant, and Foo's constructor doesn't depend on other runtime-only data, then it is possible to optimise. But, there's nothing in your code that requires the C++ Standard to even attempt any optimisation, let alone be capable of optimising this away. The same is true of the + operator invoked on the Foos... it may be legal to optimise, but is certainly not required.

In practice, I would expect most current mainstream compiler to optimise simple cases of Foo(i) for compile-time constant i, but be challenged by resolving the addition. If you really want to know, try it for your compiler at various optimisation levels....

Assuming that it executes at run-time (which I believe to be the case), is there a way to make it run at compile-time, or have the same effects as if it were run as such?

Yes... you may get some milage out of constexpr, which is a keyword introduced with C++11 that tells the compiler it's required to resolve certain values at compile time (if you constexpr for variables/values that the compiler isn't required to support at compile time it will report an error).

Secondly, it's often possible to express compile time operations using templates. To get yourself started in that direction, you may want to search for "C++ template factorial compiletime" or similar to see how basic calculations can be coded.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • 1
    Correct answer. If `Foo` is a simple wrapper around `int` and `operator+(Foo, Foo)` is just a typesafe `int+int`, then compilers might even optimize that bit. – MSalters May 24 '12 at 09:04
2

The "as-if" rules applies, which says that the compiler can do anything it likes, provided that the observable behavior of the program is the same as that described in the standard.

If:

  • the constructor of Foo is visible in the TU,
  • so is the destructor ~Foo,
  • neither of them has any side-effects,
  • their results don't depend on anything that needs to be worked out at runtime (like the time, or the value of some non-const object that for all we know might have been modified by the point your code is executed),
  • operator+ is visible, and doesn't do anything to let the address of the RHS "escape" into unknown code, or use its address for observable behavior (such as printing it out), or do anything else that requires the object actually be there,

then a sufficiently clever optimizer could eliminate the Foo(2) temporary entirely, and wherever operator+ uses the data members of the RHS, just use whatever values it knows those members will have.

Or, as a lesser optimization, it could put the values into the layout of an instance of Foo in a data section of the program, and use that as Foo(2). I guess that's what you mean by storing the result for runtime.

Whether such optimizations actually happen is completely implementation-specific, and depends what compiler you use and what flags. Disassemble the code to see what really happens.

You can ensure that Foo(2) is computed only once in C++03, if you do something like:

static Foo foo2(2);
Foo a(i), b = a + foo2;

foo2 is (according to the standard) computed at runtime, the first time the code is executed. Again, the compiler could invoke the "as-if" rule to do some or all of the computation at compile-time, but again this isn't required.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
0
Foo a(i), b = a + Foo(2);

This initialization happens at runtime, not at compile-time.

Compile-time initialization happens only for built-in types, iftheir initializer can be computed at compile-time, or if they are declared as global variables, or as static. In the latter two cases, they are zero-intialized at compile-time. I've explained this in detail here:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
0

The code which has been compiled may be called at different points during the execution process. Once the code is compiled, Foo(2)'s value might be immutable.

Drew
  • 2,583
  • 5
  • 36
  • 54
  • 1
    downvote not because you're wrong, but because I dont understand what you're saying. – Mooing Duck May 24 '12 at 05:38
  • It's wrong, too. The value of `Foo(2)` may well depend on the time of construction, and therefore not be a compile-time constant. – MSalters May 24 '12 at 09:01
-1

This happens at run time. If you want it to happen at compile time then you need to hard code the value.

zortacon
  • 617
  • 5
  • 15