Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Part Two.  Surviving the Real World


Chapter 11. Statics

Static objects are distinguished from stack variables and heap variables in that their storage is fixed and allocated by the linker, and their lifetimes are (largely) independent from the execution flow of the process. Static objects fall into three categories.

  1. Function-local static variables are those that are defined within function scope.

  2. Global and namespace-global static variables—also known as nonlocal statics—are those that are defined in the global namespace or within a named or anonymous namespace.

  3. Static member variables are those that are shared between instances of the class within which they're defined.

This chapter looks at the problems inherent in the use of static objects and suggests some measures to ameliorate them.

It's important to realize that the initialization of static objects is a two-phase operation. First, the memory they occupy is zero-initialized by the "implementation." The standard (C++-98: 3.6.2;1) states that "the zero initialization of all local objects with static storage duration is performed before any other initialization takes place." In practice this is usually carried out by the operating system process loading mechanism because the variables are placed in the .data (or .bss) segment of the link unit (executable or dynamic library), which is simply copied into a read-write memory segment [Lind1994]. In Listing 11.1, the variables i1 and i2 would both be initialized to zero.

Listing 11.1.


extern int SomeOtherModulesFunc();





namespace StaticsAbound


{


  inline int LocalFunc()


  {


    return 10;


  }


  struct Thing


  {


    Thing()


      : i(SomeOtherModulesFunc())


    {}


    int i;


  } thing;


  int i1 = 0;


  int i2;


  int i3 = 1;


  int i4 = LocalFunc();


  int i5 = ::SomeOtherModulesFunc();


}



When static objects are of POD type (see Prologue) and are initialized from constant expressions, their values can be written into the executable by the compiler, and therefore do not require any run time initialization, that is, i3 would be given the value 1 during compilation/linking. Furthermore, it is legal (C++-98: 3.6.2;2) for an implementation to make optimizations and apply static initialization in circumstances where it can determine that the dynamic initialization would result in an identical value. Hence, it would be legal for compilers to static initialize i4 to the value 10.

Zero and constant initialization are collectively known as static initialization: this is the first phase. All other initialization is known as dynamic initialization; the second phase. Dynamic initialization is required for anything that cannot be completely determined at compile time, which includes the initialization of POD types to dynamic values, as well as the construction of nonlocal static class type objects: i5 and thing in Listing 11.1.

All static initialization is carried out before any dynamic initialization. Furthermore, it is usual for all dynamic initialization of nonlocal static objects to be carried out before main() is executed, although this is not mandated by the standard. As described in (C++-98: 3.6.2;3), a nonlocal static object must be initialized before the "first use of any function or object defined in the same translation as the object to be initialised." In practice, such late initialization is rare, and the compilers with which I'm familiar do this prior to the entry of main().[1] Tellingly, (C++-98: 3.6.1;1) states that, in a free-standing environment, "start-up contains the execution of constructors for objects of namespace scope with static storage duration," which could lead one to believe that the expectation of the standards body is that dynamic initialization of nonlocal static objects is completed prior to main().

[1] Presumably this is implementation defined to cater for embedded or other non-run-of-the-mill environments.


      Previous section   Next section