This is an example of a counter that can be used to address the static initialization order fiasco. A buffer is created with std::aligned_storage, and then a Stream& points to it. Then a Stream object is created in the buffer with placement new.
// Stream.cpp
#include "Stream.h"
#include <new> // placement new
#include <type_traits> // aligned_storage
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 ();
}
This is an example given for what's sometimes called the 'Schwartz' counter. But the problem is, I've found out after asking a few questions and reading, that in C++ simply placement newing an object into a buffer does not allow you to essentially do what this is doing (aliasing a char type with a Stream ptr/ref). Apparently what would be necessary in C++ is either:
Stream* streamPtr = new (&stream) Stream (); // Assigning a pointer from the result of a
// placement new expression. Not enough simply to placement new.
See this question Or, from C++17 onward, std::launder:
Stream* streamPtr = std::launder(reinterpret_cast<Stream*>(&stream));
So you cannot just placement new into a buffer and expect it to be defined behavior, right? Which is essentially what this example has done?