Is this safe to assume that A is initialized to 1 when initializing B and C here?
struct Test {
static const int A = 1;
static const int B = A + 1;
static const int C = B + 1;
};
int main() {
printf("%i %i %i\n", Test::A, Test::B, Test::C); ==> 1 2 3
}
what about for non-integral static members
struct Test2 {
constexpr static const Test A = Test();
constexpr static const Test B = A;
constexpr static const Test C = B;
};
clang -Wall issues no warnings.
They will be initialized in the order of definition in given translation unit and before any other objects or variables.
Maybe. In this case, the initialization of A is static, so
A can be used as an integral constant expression. Which then
propagates to B. When you declare the members, they will be
initialized statically, to what the compiler has evaluated (i.e.
0 and 1), before the program even starts.
If they aren't initialized statically (which is only legal in
C++11), for any reason whatever, then they will be initialized
in the order the definitions appear in the source file, if they
are defined in the same source file. If they are not defined in
the same source file, then the order they are initialized is
unspecified.
Concerning your second example: if they are really constexpr,
there are still only constant expressions involved, so
everything will be decided at compile time, and the members will
be statically initialized.
Yes. Objects with static storage duration are always zero-initialized prior to anything else:
Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.
[3.6.2§2]
Therefore any constant or dynamic initialization may assume that all other objects with static storage duration are at least zero-initialized.
Note that this does not give any guarantees for anything other than zero-initialization!
Related
For the following code segment:
class Bar {
public:
int x;
int y;
Bar(int _x, int _y) { /* some codes here */ ...}
};
class Foo {
public:
int x;
int y;
int z;
Foo(Bar b):x(b.x), y(b.y)
{
z = someFunction(x, y);
}
};
void f(int x, int y)
{
Bar b(x, y);
static Foo x(b);
}
int main()
{
f(2, 3);
}
In my mind, a static variable inside a function should be initialized even before main(). However, the static variable x of type Foo depends on a local variable b of type Bar.
The questions are:
1) When does the constructor of x execute? i.e. Are x initialized with the first invocation of the local variable b? I don't want some particular result of some special compiler case, but want to know if it is well-defined in the C++ language.
2) Is it a valid program?
3) It it a a good practice?
In my mind, a static variable inside a function should be initialized even before main()
Your mind is incorrect... at least partly. A static local variable may be initialized early in some situations, but not in a case where the constructor depends on a local variable such as this one.
n3242 draft of the standard §6.7/4:
... An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; ...
For completeness, here is the requirements for constant (static) initialization §3.6.2/2:
Constant initialization is performed:
— if each full-expression (including implicit conversions) that appears in the initializer of a reference with
static or thread storage duration is a constant expression (5.19) and the reference is bound to an lvalue
designating an object with static storage duration or to a temporary (see 12.2);
— if an object with static or thread storage duration is initialized by a constructor call, if the constructor is
a constexpr constructor, if all constructor arguments are constant expressions (including conversions),
and if, after function invocation substitution (7.1.5), every constructor call and full-expression in the
mem-initializers is a constant expression;
— if an object with static or thread storage duration is not initialized by a constructor call and if every
full-expression that appears in its initializer is a constant expression.
1) x is initialized when the execution reaches it's declaration for the first time and that's when the constructor is run. So, b is fully initialized when the initialization of x starts.
2) As far as the initialization dependency is concerned, yes.
3) Sure, if you need that, a constructor of a static local object may depend on a local object. As long as you don't refer to that local object after the it's out of scope. In this case you simply copy it's members, so you don't depend on it after constructing x.
According to the C++ Standard (6.7 Declaration statement)
4 The zero-initialization (8.5) of all block-scope variables with
static storage duration (3.7.1) or thread storage duration (3.7.2) is
performed before any other initialization takes place. ...Otherwise
such a variable is initialized the first time control passes through
its declaration; such a variable is considered initialized upon the
completion of its initialization. If the initialization exits by
throwing an exception, the initialization is not complete, so it will
be tried again the next time control enters the declaration. ...
Thus before the function will get the control local static variables are zero-initialized and then when the function will get the control they are initialized using their initializers (or constructors).
Vlad did the hard part of finding references in C++ standard.
Now for your questions :
when will constructor of x be executed ?: per Vlad's answer, it will be executed the first time you will call f, and x will then keep its value through any other call
Is it a valid program? : the current program does not compiler but for other mistakes : x and y are private in bar, and in f, x in already a parameter. But the initialization of a static variable with the values passed at first invocation is fine
is it a a good practice? : it is not a common usage so it must be explained in a comment for following readers or maintainers. Apart from that nothing is wrong with it provided you know why you use this construct.
Quote from 3.6.2/3 of N3797 C++14 final working draft:
An implementation is permitted to perform the initialization of a
non-local variable with static storage duration as a static
initialization even if such initialization is not required to be done
statically, provided that
— the dynamic version of the initialization does not change the value
of any other object of namespace scope prior to its initialization,
and
— the static version of the initialization produces the same value in
the initialized variable as would be produced by the dynamic
initialization if all variables not required to be initialized
statically were initialized dynamically.
What does all variable have to initialization of one specific variable?
If it possible, describe the latter point by example.
This matters when the initialiser of one variable refers to another variable.
constexpr int f(int);
extern const int a = f(1); // not required to be statically initialized
extern const int b = a; // also not required to be statically initialized
constexpr int f(int x) { return x; }
Now suppose that the implementation chooses to statically initialize b, but dynamically initialize a. In that case, the initialization of b would take place before that of a. The text you ask about explains that this doesn't permit an implementation to initialize b to zero: even if b is initialized first, its value must be f(1), which is 1.
In file maybe_use_foo.cpp:
namespace {
class Foo { /* ... */ };
Foo* const the_foo = new Foo;
}
void funtion_callable_from_another_tu_during_process_wide_initialization() {
// If we haven't yet run static initialization for this TU,
// but some other static initializer called us, ignore the request.
if (!the_foo)
return;
// OK, static initializers for this TU have run, foo exists, use it.
the_foo->doSomething();
}
So, independently of whether or not the above is advisable, does it always work? It seem to me that it assumes that statics are zero-initialized before the static initialization for the TU runs. Does the C++ standard (C++03? C++11?) guarantee that?
Another way to ask the question would be to ask what sequence of values, when interpreted as a Foo*, are held in the storage for 'the_foo'. Is it definitely {NULL/nullptr, new Foo}, or is it {undefined, new Foo}, or even something else?
Please don't suggest other ways of organizing: I'm not looking for suggestions on how to do this better, I'm looking for a deeper understanding of the legality of the technique.
C++11
[basic.start.init]/2
Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.
[...]
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.
That is, yes, the variables are zero-initialized, but no, they're not zero-initialized before static initialization (but as part of static initialization).
The function in the OP will only be called during during dynamic initialization, as it is not called during zero-initialization and had to be a constexpr function to be part of constant initialization.
Yes, the C++03 standard explains in [basic.start.init]:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.
8.5.1 explains:
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
[..]
Your code can cause errors. Linkers usually don't try to deeply understand initialization portions in seperate modules. Try better to provide the variable via static function, for example
namespace {
Foo* the_foo() {
static Foo* g_ = new Foo;
return g_;
}
}
When reading the slides about constexpr the introduction is about "surprisingly dynamic initialization with consts". The example is
struct S {
static const int c;
};
const int d = 10 * S::c;
const int S::c = 5;
Alas, the audio track is missing, so are the notes, so I can only guess what is meant here.
Is it corrrect that d is "surprisingly" initialized dynamically, because S::c is defined before d? That the declaration of S::c is before d is probably not enough, the compiler needs the complete definition, right?
That said, I suspect, that in the following example d would be initialized statically?
struct S {
static const int c;
};
const int S::c = 5;
const int d = 10 * S::c; // now _after_ defn of S::c
And to take the cake, in C++11, what would have to be constexpr for full static initialization? S::c, d or both?
In the first example, d is not initialized by a constant expression, because S::c is not
a non-volatile const object with a preceding initialization,
initialized with a constant expression
(see C++11 [expr.const]p2, bullet on lvalue-to-rvalue conversions), because the initialization of S::c does not precede the initialization of d. Therefore static initialization will be used for S::c (because it is initialized by a constant expression), but dynamic initialization can be used for d.
Since static initialization precedes dynamic initialization, d would be initialized to 50 by its dynamic initializer. The compiler is permitted to convert the dynamic initialization of d to static initialization, but if it does, it must produce the value that d would have had if every variable which could have used dynamic initialization had, in fact, used dynamic initialization. In this case, d is initialized to 50 either way. See C++11 [basic.start.init]p2 for more information on this.
There is no way to add constexpr to the first example to guarantee that static initialization is used for d; in order to do that, you must reorder the initializations. However, adding constexpr will produce a diagnostic for the first example, which will at least allow you to ensure that dynamic initialization is not used (you get static initialization or a compilation error).
You can update the second case to ensure that static initialization is used as follows:
struct S {
static const int c; // do not use constexpr here
};
constexpr int S::c = 5;
constexpr int d = 10 * S::c;
It is ill-formed to use constexpr on a variable declaration which is not a definition, or to use it on a variable declaration which does not contain an initializer, so const, not constexpr must be used within the definition of struct S. There is one exception to this rule, which is when defining a static constexpr data member of a literal, non-integral type, with the initializer specified within the class:
struct T { int n; };
struct U {
static constexpr T t = { 4 };
};
constexpr T U::t;
In this case, constexpr must be used in the definition of the class, in order to permit an initializer to be provided, and constexpr must be used in the definition of the static data member, in order to allow its use within constant expressions.
I believe that the rules laid out in 3.6.2 to determine when static initialization happens do not include the initialization for d, which is therefore dynamic initialization. On the other hand, S::c is indeed statically initialized (since 5 is a constant expression). Since all static initialization happens before dynamic initialization, you get the expected result.
To make d eligible for static initialization, it has to be initialized with a constant expression. This in turn forces you to write the S::c inline:
struct S { static constexpr int c = 5; };
const int d = S::c; // statically initialized
Note that the standard permits dynamic initialization to be replaced by static initialization, which is why reordering the two lines in your original example will cause the two different sorts of initialization. As TonyK points out, you can use array[d] in the static case, but not in the dynamic case, so you can check which one is happening. With the constexpr approach, you're guaranteed to have static initialization and you don't have to rely on optional compiler behaviour.
For static initialization one needs, roughly speaking, a constant-expression initializer.
To be a constant-expression, roughly speaking, a variable needs to be of a const type and have a preceding initialization with a constant-expression.
In the first example d's initializer is not a constant-expression, as S::c isn't one (it has no preceding initialization). Hence, d is not statically initialized.
In the second example d's initializer is a constant-expression, and everything is OK.
I'm simplifying matters. In full formal standardese this would be about nine times longer.
As for constexpr specifier, no object has to be declared constexpr. It is just an additional error-check. (This is about constexpr objects, not constexpr functions).
You may declare S::c constexpr in the second variant if you want some extra error protection (perhaps 5 will start changing its value tomorrow?) Adding constexpr to the first variant cannot possibly help.
You can find out whether a constant is statically or dynamically initialised by trying to declare an array:
struct S {
static const int c;
};
const int d = 10 * S::c; // (1)
const int S::c = 5; // (2)
static char array[d];
This code fails in g++ version 4.7.0, because d is dynamically initialised. And if you exchange (1) and (2), it compiles, because now d is statically initialised. But I can't find another way to fix it, using constexpr.
Following is a simple case of counting objects:
struct A
{
static int count;
A () { ++ count; }
};
Now, its object and static member are declared as:
A obj; // comes 1st
int A::count = 5; // comes 2nd
g++ produces expected result. But since, definition of A::count comes after one of the A instance in global space, shouldn't it be undefined behavior ?
It depends.
3.6.2
The storage for objects with static
storage duration (basic.stc.static)
shall be zero-initialized (dcl.init)
before any other initialization takes
place. Zero-initialization and
initialization with a constant
expression are collectively called
static initialization; all other
initialization is dynamic
initialization. Objects of POD types
(basic.types) with static storage
duration initialized with constant
expressions (expr.const) shall be
initialized before any dynamic
initialization takes place.
Since you have a POD initialized with a constant expression, it will be statically initialized, i.e. before any constructors run. Change any of these conditions, and unexpected results are likely to occur.