6

Regarding the book "Effective C++" from Scot Meyers, and the 4th item: non-local static objects can be uninitialized before the are used (static in this case means "global", with static life). If you replace it with a local-static object, which is created inside a function that returns a reference to it, the object is then for sure initialized before use.

I always have a file with constants. I declare extern const int a; in an .hpp file and define it in the .cpp file. But can then the same thing happen? a can be uninitialized. Or not? Does the same rule apply for built-in types?

Dusan
  • 95
  • 5
  • 5
    Variables in the global scope are *always* initialized. Even if they don't have an explicit initialization when being defined, the system will [*zero-initialize*](http://en.cppreference.com/w/cpp/language/zero_initialization) them. And `const` variables must be explicitly be initialized anyway. – Some programmer dude Feb 22 '17 at 08:35
  • you may want to look at http://stackoverflow.com/questions/1005685/c-static-initialization-order – Andrew Kashpur Feb 22 '17 at 09:30
  • Hey guys, thank you! As far as I see, initialization of global objects of built-in types is always handled by compiler, never mind if they are local or non-local... – Dusan Feb 22 '17 at 09:55
  • @Dusan There are cases were the static initialization fiasco also happens for builtin types: https://wandbox.org/permlink/8Ms5K2tFtGbuxgzB. See my answer for links and details. – Jens Aug 23 '17 at 07:27

2 Answers2

3

Even though you can, it's not such a good idea to return references to "local-static" variables. The variable was (presumably) declared locally to reduce its scope to just the enclosing function, so attempting to increase its scope in this manner is rather hacky. You could make it a global variable and use something like std::call_once to guarantee it's initialized exactly once on first usage. Returning a mutable reference to a local-static object also raises thread-safety concerns because the function may no longer be re-entrant.

POD types with static storage duration are guaranteed to be zero-initialized. You can also initialize them with a constant expression and the language will guarantee they are initialized before any dynamic initialization takes place. Here's a similar question that may provide some additional insight.

v1bri
  • 1,398
  • 8
  • 13
0

The problem regarding static initialization is known as static initialization order fiasco:

In short, suppose you have two static objects x and y which exist in separate source files, say x.cpp and y.cpp. Suppose further that the initialization for the y object (typically the y object’s constructor) calls some method on the x object.

So if you have another translation unit using your constants, you have a rather good chance that your program will not work. Sometimes it is the order the files were linked together, some plattforms even define it in the doc (I think Solaris is one example here).

The problem also applies to builtin types such as int. The example from the FAQ is:

#include <iostream>
int f();  // forward declaration
int g();  // forward declaration
int x = f();
int y = g();
int f()
{
  std::cout << "using 'y' (which is " << y << ")\n";
  return 3*y + 7;
}
int g()
{
  std::cout << "initializing 'y'\n";
  return 5;
}

int main() {
    std::cout << x << std::endl << y  << std::endl;
    return 0;
}

If you run this example, the output is:

using 'y' (which is 0) initializing 'y'

So y first gets zero-initialized and then constant initialization (?) happens.

The solution is the Construct On First Use Idiom:

The basic idea of the Construct On First Use Idiom is to wrap your static object inside a function.

Static loca objects are constructed the first time the control flow reaches their declaration.

Jens
  • 9,058
  • 2
  • 26
  • 43