
Static initialization order fiasco
-
Construct On First Use Idiom
-
If the object does not need to be destructed, uses a static pointer.
1
2
3
4
5
6
7
Fred& ()
{
static Fred* ans = new Fred();
return *ans;
}1
2
3
4
5
6
7
8// File Barney.cpp
Barney::Barney()
{
// ...
x().goBowling();
// ...
}This approach is that the Fred object is never destructed.
The Construct On First Use Idiom uses a pointer and intentionally leaks the object. -
If you need to destruct the object and do not care the order of static objects deinitialization, uses a static object.
1
2
3
4
5
6
7
Fred& ()
{
static Fred ans; // was static Fred* ans = new Fred();
return ans; // was return *ans;
}It does not leak the object, but it does not control the order of static deinitialization, so it is (very!) unsafe to use the object during static deinitialization, that is, from a destructor of another statically declared object.
-
-
Nifty Counter
It is a more complicated solution that solves problems mentioned above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// Stream.h
struct Stream {
Stream ();
~Stream ();
};
extern Stream& stream; // global stream object
static struct StreamInitializer {
StreamInitializer ();
~StreamInitializer ();
} streamInitializer; // static initializer for every translation unit1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// Stream.cpp
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.




近期评论