From e393d44e92621552a6c28087114e76b3d395ece6 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 17 Mar 2018 17:30:28 +0100 Subject: [PATCH] DI: replace Meyers Singleton by an explicitly managed buffer Meyers Singleton is elegant and fast and considered the default solution However... - we want an "instance" pointer that can be rebound and reset, and thus we are forced to use an explicit Mutex and an atomic variable. And the situation is such that the optimiser can not detect/verify this usage and thus generates a spurious additional lock for Meyers Singleton - we want the option to destroy our singletons explicitly - we need to create an abstracted closure for the ctor invocation - we need a compiletime-branch to exclude code generation for invoking the ctor of an abstract baseclass or interface All those points would be somehow manageable, but would counterfeit the simplicity of Meyers Singleton --- research/try.cpp | 86 +++++++++++++++++++++++++++++++++++++--- wiki/thinkPad.ichthyo.mm | 28 ++++++++++++- 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index f8190b934..afe11ee2f 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -48,12 +48,14 @@ typedef unsigned int uint; #include "lib/format-cout.hpp" #include "lib/depend.hpp" #include "lib/depend2.hpp" +#include "lib/meta/util.hpp" //#include "lib/meta/util.hpp" #include "lib/test/test-helper.hpp" #include "lib/util.hpp" #include #include +#include #define SHOW_TYPE(_TY_) \ @@ -62,9 +64,64 @@ typedef unsigned int uint; cout << "Probe " << STRINGIFY(_XX_) << " ? = " << _XX_ < + class InstanceHolder + : boost::noncopyable + { + /** storage for the service instance */ + char buff_[sizeof(TAR)]; + bool alive_ = false; + + + public: + ~InstanceHolder() + { + if (alive_) + try { + alive_ = false; + reinterpret_cast (buff_). ~TAR(); + } + catch(...) + { // no logging since we might be in static shutdown + lumiera_error(); // reset errorflag + } + } + + + TAR* + buildInstance() + { + if (alive_) + throw error::Fatal("Attempt to double-create a singleton service. " + "Either the application logic, or the compiler " + "or runtime system is seriously broken" + ,error::LUMIERA_ERROR_LIFECYCLE); + + // place new instance into embedded buffer + TAR* newInstance = new(&buff_) TAR (); + alive_ = true; + return newInstance; + } + }; + + template + class InstanceHolder>> + { + public: + ABS* + buildInstance() + { + throw error::Fatal("Attempt to create a singleton instance of an abstract class. " + "Application architecture or lifecycle is seriously broken."); + } + }; @@ -74,14 +131,16 @@ class DependInject; template class Depend { + public: using Factory = std::function; static SRV* instance; static Factory factory; + static InstanceHolder singleton; + friend class DependInject; - public: SRV& operator() () { @@ -101,8 +160,7 @@ class Depend { if (!factory) { - static SRV singleton{}; - instance = &singleton; + instance = singleton.buildInstance(); factory = disabledFactory; } else @@ -125,17 +183,29 @@ SRV* Depend::instance; template typename Depend::Factory Depend::factory; +template +InstanceHolder Depend::singleton; + + +struct Dum + : boost::noncopyable + { + virtual ~Dum() { } + virtual int probe() =0; + }; + + int checksum = 0; template struct Dummy - : boost::noncopyable + : Dum { Dummy() { checksum += N; } ~Dummy() { checksum -= N; } - int + virtual int probe() { return N * checksum; @@ -161,6 +231,10 @@ main (int, char**) SHOW_EXPR( dep12().probe() ); SHOW_EXPR( checksum ); + Depend dumm; + Depend::factory = [](){ return nullptr; }; + SHOW_EXPR( dumm().probe() ); + cout << "\n.gulp.\n"; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 7ae326b65..8f1b18fdf 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -26995,13 +26995,39 @@ + + + + + + + + + + + + + + + + +

+ ...aber dann eben nicht mehr elegant. +

+ + +
+
+ + +
- +