cppreference states:
Variables declared at block scope with the specifier static or thread_local (since C++11) have static or thread (since C++11) storage duration but are initialized the first time control passes through their declaration (unless their initialization is zero- or constant-initialization, which can be performed before the block is first entered).
My question is about that "unless" part - can you give examples of code where the static local variable is zero- and constant-initialized? Can class objects (e.g. MyClass obj;) be zero- or constant-initialized? If so, does that mean their constructor would be called before main() starts?
can you give examples of code where the static local variable is zero- and constant-initialized?
In the below given example, the local static variable n satisfies both the conditions for constant initialization so that here the "unless" part in your quoted statement also holds.
int main()
{
static const int i = 5; //both conditions for constant initialization are satisfied so that the "unless" part of your quoted statement also holds
}
A variable or temporary object obj is constant-initialized if
either it has an initializer or its default-initialization results in some initialization being performed, and
its initialization full-expression is a constant expression, except that if obj is an object, that full-expression may also invoke constexpr constructors for obj and its subobjects even if those objects are of non-literal class types (since C++11).
Can class objects (e.g. MyClass obj;) be zero- or constant-initialized?
Yes class objects can also be constant initialized.
struct Custom
{
constexpr Custom()
{
}
};
int main()
{
static constexpr Custom obj;//here also both conditions for constant initialization are satisfied
}
Note also that initialization does not necessarily implies that a constructor must be used. For example, in #include <string> std::string s; int main(){} the s is first is zero initialized and then default initialized(using the default ctor). This means that the first initialization step here, does not use any ctor.
According to this: https://en.cppreference.com/w/cpp/language/zero_initialization
Zero-initialization is performed [...] For every named variable with static [...] storage duration that is not subject to constant initialization, before any other initialization.
So in this context
int main() {
...
static MyClass a;
...
}
zero-initialization of a can be performed before main() starts, but its constructor will be called inside of main() as expected.
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.
When are constexpr objects constructed relative to non-constexpr non-local objects with static storage duration? Do they start their life prior to initialization of any other objects, i.e., prior to dynamic initialization?
I'm contemplating whether it would be reasonable to have a string_literal class (live example) which is used, e.g., to compare std::strings against certain keywords:
class string_literal
{
// private members
public:
constexpr string_literal(char const* b);
bool operator== (std::string const& other) const;
bool operator!= (std::string const& other) const;
// other member functions
};
constexpr string_literal hello("hello");
void f(std::string const& s) {
if (s == hello) {
// do something
}
}
Since the string_literal could parse the string-literal at compile-time to locate the first null-character, I could imagine that these comparisons can be made faster than comparing a std::string against a string-literal. However, to be safe it is necessary that the hello object is readily constructed when the first constructor is executed at run-time during static initialization: otherwise these objects could be accidentally accessed when they are not, yet, constructed.
In the C++11 standard the order of initialization of non-local variables is discussed in §3.6.2 “Initialization of non-local variables”.
First static initialization is performed, then dynamic initialization.
Static initialization consists of zero-initialization followed by constant-initialization. Zero-initialization is just what it sounds like. Constant-initialization is new in C++11, and §3.6.2/2 specifies that it's 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 and in the brace-or-equal-initializers for non-static data members 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.
So, the second point is where a constexpr object is potentially initialized, as the last part of static initialization, and essentially it happens if everything is constexpr so that it can be known at compile time.
And yes, as part of the static initialization this happens before dynamic initialization.
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_;
}
}
I'd have expected the following code to yield a segmentation fault (or otherwise UB):
struct T {
T();
};
T t;
char const* str = "Test string";
T::T() {
std::cout << str; // zero-initialised, only!
}
int main() {}
That's because t is initialised before str. I'd expect str to hold the value (char const*)0 due to zero-initialisation. My interpretation of [C++11: 3.6.2/2] supports this.
However, the above snippet appears to output the string as expected (and I confirmed the behaviour by also printing the pointer's value).
Is there some rule of static initialisation that I'm missing here, that allows str to be value-initialised before t begins construction? Where is it in the standard?
This came up on static variable resolution at build time, where an answerer asserted that using char const* rather than std::string for a static global avoids the static initialisation order fiasco. I disagreed, but now I'm not so sure...
str is initialized by a constant expression and const char * is a POD type (C++03 terms, but C++11 it is analogous, but with different terms and way more allowed cases). Such an initialization is done in static initialization phase, and the static initialization phase has no issue of order. It happens before any dynamic initialization. t is initialized in the dynamic initialization phase.
Built-in types aren't initialised at all, in the normal sense. Commonly, their initial contents are memory-mapped directly from a special region of the binary as part of loading it.
I think I found it; what's happening here is not so much about the built-in type, but about the constant initialiser:
[C++11: 3.6.2/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.
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 and in the brace-or-equal-initializers for non-static data members 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.
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 final sentence would seem to override subsequent sequencing rules, making this ordering apply across Translation Units.
char const* str = "Test string";
is done by the compiler/linker, so it exists in its "initialized state" before the program even starts to run.
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.