3

I just wondered what the best way is to get rid of the globally available static getInstance() in a Singleton. I do not want my Singleton classes being accessed from every point in my program.

I thought about maybe having a create() public static function that creates one object and returns it but one cannot call this method twice.

But it's not very elegant for me. Than I would have to make an assertion or throw an exception in case create() gets called a second time.

Is there any other way I can achieve what I want?

Steve Townsend
  • 51,210
  • 8
  • 87
  • 134
tyrondis
  • 3,160
  • 5
  • 29
  • 52
  • 3
    Look at that, singletons making [more problems then they solve](http://jalf.dk/blog/2010/03/singletons-solving-problems-you-didnt-know-you-never-had-since-1995/). Why do you think it needs to be a singleton at all? What's the context? – GManNickG Oct 13 '10 at 18:02
  • what about making services from classes that need to be singletonized and then passing references to wherever you want to use them? – erjot Oct 13 '10 at 18:02
  • @GMan: I just want to prevent having more than one object. Coz' creating one a second time would damage the whole application. – tyrondis Oct 13 '10 at 18:05
  • 1
    @Benjamin: So don't make a second one. Or assert in the constructor if you really want. What you've said does not make it necessary it be globally accessible and therefore not make it necessary to be a singleton. – GManNickG Oct 13 '10 at 18:06
  • @GMan: Ok but how should the constructor know if there is already an existing object? Adding a static counter? – tyrondis Oct 13 '10 at 18:26
  • Use a static member in the class that needs this, just as you would in the Singleton. Just don't make it a 'big S' Singleton with a public static 'GetInstance' for all to see and use... See the blog post in my answer below. – Steve Townsend Oct 13 '10 at 18:36
  • @Benjamin: I added an answer. – GManNickG Oct 13 '10 at 18:44

3 Answers3

3

You said that "creating one a second time would damage the whole application.". My response is: so don't make more then one. In C++, the type system is too weak to easily ensure this at compile-time. We can still write up a utility to approximate it at run-time, though.

Note, though, that this in no way implies you should use a singleton. (You have zero need for a global; it's unfortunate the drones have associated single-instance with global). What you want is this:

#include <stdexcept>

// inherit from this class (privately) to ensure only
// a single instance of the derived class is created
template <typename D> // CRTP (to give each instantiation its own flag)
class single_instance
{
protected: // protected constructors to ensure this is used as a mixin
    single_instance()
    {
        if (mConstructed)
            throw std::runtime_error("already created");

        mConstructed = true;
    }

    ~single_instance()
    {
        mConstructed = false;
    }

private:
    // private and not defined in order to
    // force the derived class be noncopyable
    single_instance(const single_instance&);
    single_instance& operator=(const single_instance&);

    static bool mConstructed;
};

template <typename T>
bool single_instance<T>::mConstructed = false;

Now you get an exception if the class is constructed more than once:

class my_class : private single_instance<my_class>
{
public:
    // usual interface (nonycopyable)
};

int main()
{
    my_class a; // okay
    my_class b; // exception
}
GManNickG
  • 459,504
  • 50
  • 465
  • 534
  • Very nice! I think that fits my need pretty perfectly. Thanks a lot! – tyrondis Oct 13 '10 at 18:51
  • @GMan: don't bother with `atomic`, the code is not thread-safe anyway. You can still create multiple instances with the right timing when in a multi-threaded situation (you would need some form of `test-and-set` to prevent this). – Matthieu M. Oct 13 '10 at 20:04
  • @Matthieu: Oh, total duh on my part. (I've been doing *tons* of concurrency lately, for shame.) – GManNickG Oct 13 '10 at 20:23
  • 1
    Down-vote comment? Cannot improve if I don't know what's wrong. – GManNickG Oct 13 '10 at 20:29
  • @GMan: I just encountered one tiny problem with your solution. The destructor should reset mCreated to false if one wants to reuse the class. – tyrondis Oct 17 '10 at 14:59
2

Remove the Singleton and re-insert the enclosed function to where it should actually be, with appropriate access modifiers.

See here for a definitive list of reasons why singletons are an antipattern.

Especialy important - see here for the different between Singleton (the GoF pattern) and singleton (as in 'there is one and only one of me').

Community
  • 1
  • 1
Steve Townsend
  • 51,210
  • 8
  • 87
  • 134
1

You could make your getInstance() method protected, and allow access via friend declarations. You'll have to manually "whitelist" classes with access to getInstance() both by adding a friend declaration.

class Singleton {
protected:
  static Singleton* getInstance() { return Singleton::s_instance_; }
  // Allow access to SingletonUser
  friend class SingletonUser;
private:
  Singleton() { }
  static Singleton* s_instance_;
};

class SingletonUser {
public:
  void doStuff() {
    // Fails if not a friend of Singleton
    Singleton* s = Singleton::getInstance();
  }
};
meager
  • 209,754
  • 38
  • 307
  • 315