简体   繁体   中英

inline variable emulation: can I use global static references to enforce the initialization order of static variable in functions?

N4424 introduces inline variables (ones that can be defined in multiple translation units, useful in header-only libraries), but it is not in C++14. I have been using the following method to emulate it:

// a.hpp
#pragma once // to simplify
inline A& a_init() { static A a_obj; return a_obj; }
static A& a = a_init();

and

// b.hpp
#pragma once // to simplify
#include "a.hpp"
inline B& b_init() { static B b_obj{ use(a) }; return b_obj; }
static B& b = b_init();

The cpp files uses a and b . Nothing else uses a_init and b_init .

I think that:

  1. a must be initialized before b , in every translation unit that includes b ;
  2. As nothing else calls b_init , b_init is only called when initializing b . From 1 at that time a must have been initialized ( a_init must have returned);
  3. a_obj is initialized when a_init is called , so is b_obj for b_init ;
  4. Combining 2 and 3, a_obj and a are initialized before the calling of b_init , thus the use(a) is safe and the initialization order must be A() < B() ( A() returns, then B() is called);
  5. Destructors run in the reverse order of the completion of their construction , so ~B() < ~A() .

Is my reasoning correct? Is this a working emulation of inline A a; inline B b{ use(a) }; inline A a; inline B b{ use(a) }; and guarantees the order of A() < B() < ~B() < ~A() ?

Initialization order of static variables defined in different translation units (ie, .cpp files) can evoke the so called static initialization order fiasco .

Fortunatelly, there's a way to prevent this fiasco using the Construct On First Use Idiom . What you have done resembles that idiom a lot.

Now concerning your case: Due to the fact that header "b.hpp" includes header "a.hpp" before the definition of b . When including "b.hpp" in a translation unit, "a.hpp" will also be included. The preprocessor will replace the include directives with the code of headers "a.hpp" and "b.hpp" respectively, and because #include "a.hpp" is above the definition of b , a will be defined before b due to the fact that "within the same compilation unit the order is well defined (ie, the same order as definition)". Thus, you are forcing the correct order of definition.

Consequently, your reasoning holds. I don't know though if this is a working emulation of inline A a; inline B b{ use(a) }; inline A a; inline B b{ use(a) }; .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM