Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

No no no no no. This approach still needs heap allocation, and you still need to chase a pointer for every access to your singleton. That's silly. There's a much better way. Here it is, roughly speaking.

  template<typename T>
  struct singleton_bss {
      T& get() {
          return * ((T*) &this->buffer[0]);
      }
  
      void init(T&& value) {
          new ( (T*) &this->buffer[0] ) T(std::forward<T>  (value));
      }
    
      union {
          char buffer[sizeof(T)];
          long align; // adjust to taste
      };
  };

  singleton_bss<mything> g_thing;
This approach has the huge advantage of not doing any heap allocation. The storage for g_thing lives directly in bss, the portion of your processes' address space initialized by the operating system. g_thing.init() cannot fail if T's constructor is non-throwing --- singleton_bss allocates no memory!

Access to g_thing is much more efficient than access to a typical singleton. There's no pointer-to-the-instance stored in the singleton, so there's no pointer chasing. Access to g_thing is exactly as efficient as access to a plain global variable, which is as efficient as variable access can be.

You can trivially construct a version of singleton_bss that does lazy initialization, takes multiple parameters, destroys the object on module unload, and so on.



Here is the C++11 way of specifying alignment :

    alignas(T) char buffer[sizeof(T)];
Or better still, just use the unrestricted union feature :

    union {
      T t;
    };
Just use &t in place of buffer.


Thanks for the tip --- alignas slipped my mind. The compiler I use for most of my work doesn't yet support alignas (or unrestricted unions). I believe a VC++-specific equivalent would for the former trick would be __declspec(align(__alignof(T))).


Yeah, you are right, alignas is still unsupported in many compilers. clang 3.2 supports it. However, unrestricted unions has been supported in many compilers for a long time now. I would use that in this case, since you already know the type 'T'.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: