11

I read several posts on C++ initialization from Google, some of which direct me here on StackOverflow. The concepts I picked from those posts are as follows:

  • The order of initialization of C++ is:
    1. Zero Initialization;
    2. Static Initialization;
    3. Dynamic Initialization.
  • Static objects (variables included) are first Zero-initialized, and then Static-initialized.

I have several inquiries as to the initialization issue (storage class issue may be related as well):

  • Global objects (defined without static keyword) are also static objects, right?
  • Global objects are also initialized like static objects by two steps like above, right?
  • What is the Static Initialization? Does it refer to initializing static objects (defined with static keyword)?
  • I also read that objects defined within block (i.e. in a function) with static keyword is initialized when the execution thread first enters the block! This means that local static objects are not initialized before main function execution. This means they are not initialized as the two steps mentioned above, right?
  • Dynamic initialization refers to initialization of objects created by new operator, right? It might refer to initialization like myClass obj = myClass(100); or myClass obj = foo();

I have too many inquiries on the initialization and storage class specifier issues. I read the C++2003 Standard document, but cannot find a clear logic since they are scattered throughout the document.

I hope you give me an answer that logically explains the whole map of storage class specifier and initialization. Any reference is welcome!

Code that might explain my question:

class myClass{
public:
   int i;
   myClass(int j = 10): j(i){}
   // other declarations
};

myClass obj1;//global scope
static myClass obj2(2);//file scope
{   //local scope
   myClass obj3(3);
   static myClass obj4(4);
}

EDIT:
If you think my question is rather tedious, you can help explain your ideas based on the code above.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Zachary
  • 1,633
  • 2
  • 22
  • 34

2 Answers2

22

I read several posts on C++ initialization from Google, some of which direct me here on StackOverflow. The concepts I picked from those posts are as follows:

  • The order of initialization of C++ is:
    1. Zero Initialization;
    2. Static Initialization;
    3. Dynamic Initialization.

Yes, indeed there are 3 phases (in the Standard). Let us clarify them before continuing:

  • Zero Initialization: the memory is filled with 0s at the byte level.
  • Constant Initialization: a pre-computed (compile-time) byte pattern is copied at the memory location of the object
  • Static Initialization: Zero Initialization followed by Constant Initialization
  • Dynamic Initialization: a function is executed to initialize the memory

A simple example:

int const i = 5;     // constant initialization
int const j = foo(); // dynamic initialization
  • Static objects (variables included) are first Zero-initialized, and then Static-initialized.

Yes and no.

The Standard mandates that the objects be first zero-initialized and then they are:

  • constant initialized if possible
  • dynamically initialized otherwise (the compiler could not compute the memory content at compile-time)

Note: in case of constant initialization, the compiler might omit to first zero-initialized memory following the as-if rule.

I have several inquiries as to the initialization issue (storage class issue may be related as well):

  • Global objects (defined without static keyword) are also static objects, right?

Yes, at file scope the static object is just about the visibility of the symbol. A global object can be referred to, by name, from another source file whilst a static object name is completely local to the current source file.

The confusion stems from the reuse of the world static in many different situations :(

  • Global objects are also initialized like static objects by two steps like above, right?

Yes, as are local static objects in fact.

  • What is the Static Initialization? Does it refer to initializing static objects (defined with static keyword)?

No, as explained above it refers to initializing objects without executing a user-defined function but instead copying a pre-computed byte pattern over the object's memory. Note that in the case of objects that will later be dynamically initialized, this is just zero-ing the memory.

  • I also read that objects defined within block (i.e. in a function) with static keyword is initialized when the execution thread first enters the block! This means that local static objects are not initialized before main function execution. This means they are not initialized as the two steps mentioned above, right?

They are initialized with the two steps process, though indeed only the first time execution pass through their definition. So the process is the same but the timing is subtly different.

In practice though, if their initialization is static (ie, the memory pattern is a compile-time pattern) and their address is not taken they might be optimized away.

Note that in case of dynamic initialization, if their initialization fails (an exception is thrown by the function supposed to initialize them) it will be re-attempted the next time flow-control passes through their definition.

  • Dynamic initialization refers to initialization of objects created by new operator, right? It might refer to initialization like myClass obj = myClass(100); or myClass obj = foo();

Not at all, it refers to initialization requiring the execution of a user defined function (note: std::string has a user-defined constructor as far as the C++ language is concerned).

EDIT: My thanks to Zach who pointed to me I erroneously called Static Initialization what the C++11 Standard calls Constant Initialization; this error should now be fixed.

Community
  • 1
  • 1
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Matthieu, your explanation is deadly useful. Global or static objects (local or not) are firstly **zero-initialized** at compile time (linking stage), and then **statically initialized** at compile time or **dynamically initialized** at load time (just before main function). – Zachary Jul 23 '13 at 07:44
  • In your example, they are two integers. So what if two objects. For example as in my code, `myClass obj1; myClass obj2 = myClass(10); myClass obj3(20); myClass obj4 = foo();`. Does these objects all need dynamic initialization or static initialization at the 2nd initialization step? – Zachary Jul 23 '13 at 07:47
  • @Zack: they would normally need dynamic initialization, however the compiler is allowed to replace this with static initialization under the as-if rules if it can prove that you will not notice the change. – Matthieu M. Jul 23 '13 at 07:50
  • Matthieu, could you verify my first comment? True or not. What the **as-if rule** you mentioned refer to? BTW, if the 2nd step is static initialization, then when the zero and static initialization happen? Since they are both in compile time computed at byte level, what is rationale of **first set to 0, then set to some other value like 5**? – Zachary Jul 23 '13 at 08:02
  • @Zack: the "as-if" rule is that optimizations are allowed as long as the observable behavior is "as-if" they had not occurred. The idea of zero initializing and *then* static initializing is that some OS will first zero out the memory that they allocate before handing it over to the program that can then `memcpy` an image over it, but in practice this is not observable (since from the program you can only access memory after static initialization ended). – Matthieu M. Jul 23 '13 at 12:11
  • From C++2003 3.6.2/1 *Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) 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.* This means that **zero-initialization belongs to static initialization**. So the two steps should be **firstly static initialization**, and **secondly dynamically initialization**. **NOT** firstly Zero-initialization and then static or dynamic initialization. – Zachary Jul 24 '13 at 02:24
  • Indeed, though it remains that there two steps to static initialization (according to the first sentence): zero-initialization and "initialization with a constant expression" (which I had incorrectly called static initialization, apparently). I just checked the C++11 Standard and they dubbed the second step "constant initialization", which is definitely easier to pronounce. I'll edit this in. – Matthieu M. Jul 24 '13 at 06:36
  • There seems to be a mistake, `int const i = 5; ` is **const init**,not **static init** – choxsword Mar 19 '18 at 09:00
  • and here [cppref](http://en.cppreference.com/w/cpp/language/initialization) says **const initialization** takes first. – choxsword Mar 19 '18 at 09:03
  • @bigxiao: CppReference actually says "If permitted" before "first" because the wording changed in C++14 (see http://en.cppreference.com/w/cpp/language/constant_initialization). In practice, it doesn't matter, because both zero and constant initializations occur before dynamic initialization starts, and therefore the effects are not observable from the user point of view. – Matthieu M. Mar 19 '18 at 10:43
-4

I believe there are three different concepts: initializing the variable, the location of the variable in memory, the time the variable is initialized.

First: Initialization

When a variable is allocated in memory, typical processors leave the memory untouched, so the variable will have the same value that somebody else stored earlier. For security, some compilers add the extra code to initialize all variables they allocate to zero. I think this is what you mean by "Zero Initialization". It happens when you say:

 int i; // not all compilers set this to zero

However if you say to the compiler:

 int i = 10;

then the compiler instructs the processor to put 10 in the memory rather than leaving it with old values or setting it to zero. I think this is what you mean by "Static Initialization".

Finally, you could say this:

 int i;
 ...
 ...
 i = 11;

then the processor "zero initializes" (or leaves the old value) when executing int i; then when it reaches the line i = 11 it "dynamically initializes" the variable to 11 (which can happen very long after the first initialization.

Second: Location of the variable

There are: stack-based variables (sometimes called static variables), and memory-heap variables (sometimes called dynamic variables).

Variables can be created in the stack segment using this:

int i;

or the memory heap like this:

int *i = new int;

The difference is that the stack segment variable is lost after exiting the function call, while memory-heap variables are left until you say delete i;. You can read an Assembly-language book to understand the difference better.

Third: The time the variable is initialized

A stack-segment variable is "zero-initialized" or statically-initialized" when you enter the function call they are defined within.

A memory-heap variable is "zero-initialized" or statically-initialized" when it is first created by the new operator.

Final Remark

You can think about static int i; as a global variable with a scope limited to the function it is defined in. I think the confusion about static int i; comes because static hear mean another thing (it is not destroyed when you exit the routine, so it retains its value). I am not sure, but I think the trick used for static int i; is to put it in the stack of main() which means it is not destroyed until you exit the whole program (so it retains the first initialization), or it could be that it is stored in the data segment of the application.

Community
  • 1
  • 1
d777
  • 100
  • 1
  • 2
  • 10
  • Comparing my answer to that of Matthieu M., I cannot see much difference! Strange! – d777 Jul 23 '13 at 16:20
  • 2
    Well, at least three people disagree. Specifically - your definition of 'static initialization' is wrong, your description of `static int i` as a "stack based variable" is wrong, and the statement that you need to read about assembly language to understand more about dynamic allocation is wrong. Besides that, your code example for `new` is wrong. There's more, too, but it's hardly worth picking it apart more when there's another perfectly correct answer already. – Carl Norum Jul 23 '13 at 16:57
  • "When a variable is allocated in memory, typical processors leave the memory untouched, so the variable will have the same value that somebody else stored earlier." - the part after "so" is wrong. Being able to read someone else's memory is something no multi-user OS allows. – Craig S. Anderson Jul 02 '15 at 08:19