views:

850

answers:

5

If I have a class called Test ::

class Test
{
    static std::vector<int> staticVector;
};

when does staticVector get constructed and when does it get destructed ?

Is it with the instantiation of the first object of Test class, or just like regular static variables ?

Just to clarify, this question came to my mind after reading Concepts of Programming Languages (Sebesta Ch-5.4.3.1) and it says ::

Note that when the static modifier appears in the declaration of a variable in a class definition in C++, Java and C#, it has nothing to do with the lifetime of the variable. In that context, it means the variable is a class variable, rather than an instance variable. The multiple use of a reserved word can be confusing particularly to those learning the language.

did you understand? :(

+9  A: 

Exactly like regular static (global) variables.

Magnus Hoff
The only point to make in addition to this is that the order of static/global variable construction is undefined.
Skizz
I would also add that this is how variables in any namespaces are created. Globals and non-globals (**`std::cout`** is an example).
Johannes Schaub - litb
@skizz: In a particular compilation unit the order is well defined as the order of declaration. Across multiple compilation units it is undefined (or unspecified). But the question is about destruction.
Martin York
The order of destruction of static/global variables is the reverse order of creation.
Martin York
Some nit-pick, but important nit-pick: Order depends on their definition-order, not their declaration-order: In the following code, a is created after b, even though a is declared before b: **`extern A a; B b(a); A a;`** - this code may yield surprising results.
Johannes Schaub - litb
+4  A: 

It gets constructed at the same time the global variables get constructed and destructed along with the globals as well.

Goz
No static function variables are created on first use. If they are not used then they are never created. Also because they are created on first use their order is dependent on the order the functions/methods are called.
Martin York
Yeah but he wasn't asking about static function variables ... but yes .. you are right.
Goz
+1  A: 

Simply speaking:
A static member variable is constructed when the global variables are constructed. The construction order of global variables is not defined, but it happens before the main-function is entered.

Destruction happens when global variables are destroyed.

Global variables are destroyed in the reversed order they were constructed; after exiting the main-function.

Regards,
Ovanes

P.S.: I suggest to take a look at C++-Standard, which explains (defines) how and when global or static member variables are constructed or destructed.

P.P.S.: Your code only declares a static member variable, but does not initialize it. To initialize it you must write in one of the compilation units:

std::vector Test::staticVector;
or
std::vector Test::staticVector=std::vector(/* ctor params here */);

ovanes
+1  A: 

Some specific VC++ information in case that's what you're using:

  1. Static class variables construction occurs at same time as other static/global variables.
  2. In windows, the CRT startup function is responsible for this construction. This is the actual entry point of most programs you compile (it is the function which calls your Main/Winmain function). In addition, it is responsible for initializing the entire C runtime support (for example you need it to use malloc).
  3. The order of construction is undefined, however when using the microsoft VC compiler the order of construction for basic types will be OK, for example it is legal and safe to write

statics.h: ... MyClass declaration ... static const int a; static int b; static int ar[]; } statics.cpp:

const int MyClass::a = 2;
int MyClass::b = a+3;
int MyClass::ar[a] = {1,2}
Danra
The question relates to C++ and not Visual C++ or Windows. Latest versions of MSVC are pretty standard conform, but you can't use a single compiler as a reference or evidence. The Standard should be the definite source on which you should rely. Lifetime of a global or static member variables and their initializations are very well covered by the standard. Why do you use static specifier for non-member variables? This will make them have internal linkage! I think you will have linking errors in other compilation units as statics.cpp.
ovanes
+6  A: 

I want to write some text about initializaton too, which i can later link to.


First the list of possibilities.

  • Namespace Static
  • Class Static
  • Local Static

Namespace Static

  • There are two initialization methods. static (intended to happen at compile time) and dynamic (intended to happen at runtime) initialization.
  • Static Initialization happens before any dynamic initialization, disregarding of translation unit relations.
  • Dynamic Initiaization is ordered in a translation unit, while there is no particular order in static initialization. Objects of namespace scope of the same translation unit are dynamically initialized in the order in which their definition appears.
  • POD type objects that are initialized with constant expressions are statically initialized. Their value can be relied on by any object's dynamic initialization, disregarding of translation unit relations.
  • If the initialization throws an exception, std::terminate is called.

Examples:

The following program prints A(1) A(2)

struct A { 
  A(int n) { std::printf(" A(%d) ", n); } 
};

A a(1);
A b(2);

And the following, based on the same class, prints A(2) A(1)

extern A a;
A b(2);
A a(1);

Let's pretend there is a translation unit where msg is defined as the following

char const *msg = "abc";

Then the following prints abc. Note that p receives dynamic initialization. But because the static initialization (char const* is a POD type, and "abc" is an address constant expression) of msg happens before that, this is fine, and msg is guaranteed to be correctly initialized.

extern const char *msg;
struct P { P() { std::printf("%s", msg); } };
P p;
  • Dynamic initialization of an object is not required to happen before main at all costs. The initialization must happen before the first use of an object or function of its translation unit, though. This is important for dynamic loadable libraries.

Class Static

  • Behave like namespace statics.
  • There is a bug-report on whether the compiler is allowed to initialize class statics on the first use of a function or object of its translation unit too (after main). The wording in the Standard currently only allows this for namespace scope objects - but it seems it intends to allow this for class scope objects too. Read Objects of Namespace Scope.
  • For class statics that are member of templates the rule is that they are only initialized if they are ever used. Not using them will not yield to an initialization. Note that in any case, initialization will happen like explained above. Initialization will not be delayed because it's a member of a template.

Local Static

  • For local statics, special rules happen.
  • POD type objects initialized with constant expression are initialized before their block in which they are defined is entered.
  • Other local static objects are initialized at the first time control passes through their definition. Initialization is not considered to be complete when an exception is thrown. The initialization will be tried again the next time.

Example: The following program prints 0 1:

struct C { 
  C(int n) { 
    if(n == 0)
      throw n;
    this->n = n;
  }
  int n;
};

int f(int n) {
  static C c(n);
  return c.n;
}

int main() {
  try { 
    f(0); 
  } catch(int n) { 
    std::cout << n << " "; 
  }
  f(1); // initializes successfully
  std::cout << f(2);  
}


In all the above cases, in certain limited cases, for some objects that are not required to be initialized statically, the compiler can statically initialize it, instead of dynamically initializing it. This is a tricky issue, see this answer for a more detailed example.

Also note that the order of destruction is the exact order of the completion of construction of the objects. This is a common and happens in all sort of situations in C++, including in destructing temporaries.

Johannes Schaub - litb
Excellent explanation.
AraK
@AraK, thanks :)
Johannes Schaub - litb