views:

148

answers:

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?

+1  A: 

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();
  }
};
meagar
The forward declaration of `SingletonUser` is unnecessary.
Steve M
@Steve Thanks; I'm badly out of touch with C++.
meagar
Although it is an answer to the question. Why encourage such flawed design at all?
ronag
+2  A: 

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').

Steve Townsend
Yes a list of anti-reasons written by a set of developers that have had bad experience because they did not sit down and think about it before hand. The trouble is that Singleton is easy to do incorrectly so a lot of people have; and don't they wine. The problems with Singleton is not the Singleton nature but the bad usage of it: defining a singleton to have `global accessible` `mutable state` is a bad idea (unfortunately this is also the easiest way to teach what a singleton is and thus why so many people use it incorrectly) http://tiny.cc/l3l0iyx61e Though there are usually better techniques
Martin York
+2  A: 

You said that "creating one a second time would damage the whole application.". My response is: so don't make more then one.

In any case, this in no way implies you should use a singleton. (You have zero need for a global.) If you really want, what you're looking for is an assert of some sort, followed by a call to abort() (this is a bug after all):

template <typename T>
class single_instance
{
protected:
    single_instance()
    {
        assert(!mCreated);
        if (mCreated)
        {
            std::cerr << "Created two instances of: "
                        << typeid(T).name() << std::endl;
            std::abort(); // don't let it harm the application
        }

        mCreated = true;
    }

    ~single_instance() {} // not a public base class

private:
    single_instance(const single_instance&); // noncopyable
    single_instance& operator=(const single_instance&);

    static bool mCreated;
};

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

class foo : private single_instance<foo>
{
    // ...
};

Now you get an assert and abort if someone makes more than one, in a far less intrusive manner. This is much more sane.

GMan
Very nice! I think that fits my need pretty perfectly. Thanks a lot!
Benjamin
@Benjamin: No problem.
GMan
@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.
@Matthieu: Oh, total duh on my part. (I've been doing *tons* of concurrency lately, for shame.)
GMan
Down-vote comment? Cannot improve if I don't know what's wrong.
GMan
@GMan: I just encountered one tiny problem with your solution. The destructor should reset mCreated to false if one wants to reuse the class.
Benjamin
@Benjamin: Sure. I was thinking it would be one for the entire lifetime of the application.
GMan