Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constructor execution sequence/order: dependent initialization of static variable (class instance) in a function

Tags:

c++

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?

like image 336
Robin Hsu Avatar asked Sep 27 '22 14:09

Robin Hsu


2 Answers

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.

like image 145
eerorika Avatar answered Sep 30 '22 08:09

eerorika


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).

like image 20
Vlad from Moscow Avatar answered Sep 30 '22 08:09

Vlad from Moscow