Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I change static variable initialization order in C++?

I use C++ in Visual Studio 2015 sp3. By

#pragma init_seg(compiler)

, I initialize some static variables first(to memory management). https://msdn.microsoft.com/en-us/library/7977wcck.aspx

But, there is

#pragma init_seg(compiler)

in wcerr.cpp(Microsoft Visual Studio 14.0\VC\crt\src\stl\wcerr.cpp), so these objects are initialized before my objects.

Can I compel my object to be initialized first before wcerr.cpp objects by any compile / link options?

like image 809
P-P Avatar asked Dec 09 '16 07:12

P-P


People also ask

Can you modify static variables in C?

When static keyword is used, variable or data members or functions can not be modified again. It is allocated for the lifetime of program.

Can static variables be changed after being initialized?

If you declare a static variable in a class, if you haven't initialized it, just like with instance variables compiler initializes these with default values in the default constructor. Yes, you can also initialize these values using the constructor.

What is the order of static variable initialization across one program?

Within a single compilation unit, static variables are initialized in the same order as they are defined in the source (this is called Ordered Dynamic Initialization). Across compilation units, however, the order is undefined: you don't know if a static variable defined in a.

How are static variables initialized in C?

In C, static variables can only be initialized using constant literals. For example, following program fails in compilation. If we change the program to following, then it works without any error.


2 Answers

One of solutions is to try wrap your static variables to static functions:

static type& My_static_obj() {
    static type my_static_obj_;
    return my_static_obj_;
}

It looks like a simple type of Singleton and calls Construct On First Use Idiom. Due to standard (C++11 and above) it guaranteed to be initialized once (and even atomically!), and inside its c-tor such an object can access to other "static" variables, so, if there aren't circular dependencies between variables, the order of initialization will be strictly defined.

For additional information see this question and other descriptions of this Construct On First Use Idiom.

like image 133
Trollliar Avatar answered Oct 17 '22 17:10

Trollliar


Probably the nifty counter idiom can help you somehow in this case:

Ensure a non-local static object is initialized before its first use and destroyed only after last use of the object.

Its motivation is pretty clear:

When static objects use other static objects, the initialization problem becomes more complex. A static object must be initialized before its use if it has non-trivial initialization. Initialization order of static objects across compilation units is not well-defined. Multiple static objects, spread across multiple compilation units, might be using a single static object. Therefore, it must be initialized before use. One example is std::cout, which is typically used by a number of other static objects.

It's worth it to copy and paste directly the example from the above linked page:

Stream.h

#ifndef STREAM_H
#define STREAM_H

struct Stream {
  Stream ();
  ~Stream ();
};
extern Stream& stream; // global stream object

static struct StreamInitializer {
  StreamInitializer ();
  ~StreamInitializer ();
} streamInitializer; // static initializer for every translation unit

#endif // STREAM_H

Stream.cpp

#include "Stream.h"

#include <new>         // placement new
#include <type_traits> // aligned_storage

static int nifty_counter; // zero initialized at load time
static typename std::aligned_storage<sizeof (Stream), alignof (Stream)>::type
  stream_buf; // memory for the stream object
Stream& stream = reinterpret_cast<Stream&> (stream_buf);

Stream::Stream ()
{
  // initialize things
}
Stream::~Stream ()
{
  // clean-up
} 

StreamInitializer::StreamInitializer ()
{
  if (nifty_counter++ == 0) new (&stream) Stream (); // placement new
}
StreamInitializer::~StreamInitializer ()
{
  if (--nifty_counter == 0) (&stream)->~Stream ();
}

The header file of the Stream class must be included before any member function can be called on the Stream object. An instance of the StreamInitializer class is included in each compilation unit. Any use of the Stream object follows the inclusion of the header, which ensures that the constructor of the initializer object is called before the Stream object is used.

See the link above for further details.

like image 30
skypjack Avatar answered Oct 17 '22 18:10

skypjack