A Singleton that is not globally accessible

2020-04-11 04:15发布

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?

3条回答
做个烂人
2楼-- · 2020-04-11 04:54

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

查看更多
ゆ 、 Hurt°
3楼-- · 2020-04-11 05:08

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();
  }
};
查看更多
你好瞎i
4楼-- · 2020-04-11 05:17

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
}
查看更多
登录 后发表回答