2

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?

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • How about wrapping "global" in a function `Stream& getGlobalStream() { static Stream stream; return stream; }`? – Jarod42 Sep 03 '21 at 08:47
  • 1
    I think it works in practice, but it should be pedantically UB (at the time of the cast, there are no object there) (and C++17 add `std::launder` requirement too). – Jarod42 Sep 03 '21 at 08:55
  • Maybe (one-element) `union` instead of `std::aligned_storage` could work? – Alex Guteniev Sep 03 '21 at 08:56

0 Answers0