1

I have two managers (which are singletons):

  1. A licenses manager, counting licences tokens when functionalities are used. The destructor of this release all the licences.
  2. A Python manager, managing calls to Python from C++, it requires a specific license from the licences manager. The destructor calls the licences manager to finalize the license usage.

I suppose the order of destruction of the singleton is undefined. How can I avoid the mismatch at the destruction of the managers? Is it possible?

This is my typical implementation of a singleton:

class Manager : private boost::noncopyable
{
  private:
    struct singleton_deleter { void operator () (Manager* m) { delete m; } };
    friend struct Manager::singleton_deleter;

  private:
    boost::mutex                singleton_mutex;
    boost::shared_ptr<Manager>  singleton_instance;

  public:
    static Manager&  instance()
    {
      if(!(bool)Manager::singleton_instance)
      {
        boost::mutex::scoped_lock lock(Manager::singleton_mutex);
        if(!(bool)Manager::singleton_instance)
          Manager::singleton_mutex.reset(new Manager, Manager::singleton_deleter());
      }
      return *Manager::singleton_instance;
    }

  private:
    Manager() { this->lic = LicManager::instance().getLicense(); }
    ~Manager() { LicManager::instance().releaseLicense(this->lic); }
};
jotik
  • 17,044
  • 13
  • 58
  • 123
Caduchon
  • 4,574
  • 4
  • 26
  • 67
  • If you really need a Singleton, make sure you only have ***one*** in your whole system architecture. – πάντα ῥεῖ Jun 30 '16 at 12:44
  • 1
    Have one *Super*-singleton, that owns all the others! – BoBTFish Jun 30 '16 at 12:49
  • Is it really a so restrictive pattern than you can not have two different classes implemented as singletons ??? If it's true, singleton looks like a useless pattern... – Caduchon Jun 30 '16 at 12:49
  • 1
    As a side note, I think that all accesses of `Manager::singleton_instance` should be synchronized under an exclusive `Manager::singleton_mutex` lock in `Manager::instance()` to be safe. – jotik Jun 30 '16 at 12:57
  • Singletons are considered by many (including me) to be an anti-pattern that cause more problems in the long run than it solves and should be avoided in the first place in new code and killed on sight in legacy code. – Jesper Juhl Jun 30 '16 at 13:32

2 Answers2

1

Note that since the destruction order of static objects in C++ is the reverse of their construction order, you can make the constructor of one singleton first construct the other singleton it depends on as a function-local static object. For example:

LicManager & LicManager::instance() {
    static LicManager licenceManager;
    return licenceManager;
}

Manager & Manager::instance() {
    static Manager manager(LicManager::instance());
    return manager;
}

Another way would be to use a shared_ptr to share ownership of the singleton, enforcing the destruction order. Make instance() return a shared_ptr instead of a reference. In your use case, store the return value of LicManager::instance() (e.g. a shared_ptr<LicManager>) in your Manager object. This forces LicManager to stay alive for the lifetime of Manager, even if the respective LicManager shared pointer in the global scope is destroyed.

Edit: As pointed out in the comments, yet another solution would be to have only one super singleton which owns all the others and controls the initialization/destruction order.

Community
  • 1
  • 1
jotik
  • 17,044
  • 13
  • 58
  • 123
  • 1
    The definition of the static local object must be surrounded by a lock (like the `new` expression in OP), unless you can somehow guarantee that no threads are started before the singleton is first constructed, or unless you can rely on c++11 support. – eerorika Jun 30 '16 at 13:21
1

Store the singleton instance as a static local variable of the accessor function that returns a reference to it. In other words, use the Construct On First Use Idiom.

Then call the accessor function of singleton A, from the constructor of singleton B. This ensures that, the singleton A is constructed before B, which in turn ensures that A is destroyed after B.

There is a variation of this pattern which is to use - instead of a function local static object - a function local static raw pointer to a dynamic object, which is leaked on termination. That approach does not need the constructor of a singleton to call the accessor of another, but of course memory analysers will complain. The idea is that that the singleton is never destroyed, so you are free to depend on it in the destructors of other static objects.

Is it really a so restrictive pattern than you can not have two different classes implemented as singletons ??? If it's true, singleton looks like a useless pattern...

Singleton is a very restrictive pattern, and some might argue that it is useless. But it is not true that you couldn't have two different singleton classes.

eerorika
  • 232,697
  • 12
  • 197
  • 326