Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Managing a singleton destructor

Tags:

c++

c++11

The following small example implements a singleton pattern that I've seen many times:

#include <iostream>

class SingletonTest {
private:
  SingletonTest() {}
  static SingletonTest *instance;
  ~SingletonTest() {
    std::cout << "Destructing!!" << std::endl;
  }

public:
  static SingletonTest *get_instance()  {
    if(!instance) instance = new SingletonTest;
    return instance;
  }
};

SingletonTest *SingletonTest::instance = 0;

int main(int argc, char *argv[]) {
  SingletonTest *s = SingletonTest::get_instance();

  return 0;
}

The main problem I have with this is that the destructor of my singleton is never called.

I can instead make instance a (c++0x?) shared_ptr, which works well - except that it means my destructor has to be public.

I could add a static 'cleanup' method but that opens up the possibility of user error (i.e. forgetting to call it). It would also not allow for proper cleanup in the face of (unhandled) exceptions.

Is there a common strategy/pattern that will allow lazy instantiation, 'automatically' call my destructor, and still allow me to keep the destructor private?

like image 304
sje397 Avatar asked Aug 09 '11 08:08

sje397


2 Answers

...not exactly a direct answer, but too long for a comment - why not do the singleton this way:

class SingletonTest {
private:
  SingletonTest() {}
  ~SingletonTest() {
    std::cout << "Destructing!!" << std::endl;
  }

public:
  static SingletonTest& get_instance()  {
    static SingletonTest instance;
    return instance;
  }
};

Now you have a lazy singleton that will be destructed on exit... It's not any less re-entrant than your code...

like image 159
Nim Avatar answered Nov 08 '22 05:11

Nim


You could write a deinitialization function and call atexit() inside the object constructor to register it. Then when C++ runtime deinitializes the module it will at some point after main() call your deinitialization function. That bold italic is there because you get rather loose control on when exactly it is called and that can lead to deinitialization order fiasco - be careful.

like image 20
sharptooth Avatar answered Nov 08 '22 04:11

sharptooth