C ++ Майер Синглтон с аргументами - PullRequest
0 голосов
/ 07 марта 2020

Можно ли определить синглтон Мейера (например, этот ) с аргументами?

Я знаю, что это возможно с синглтоном в стиле GOF (например, здесь ),

но я не могу заставить его работать с синглтонами Майера:

// ...
public:

    static S& getInstance()
    {
        static S instance; // no way to pass arguments here ...
        return instance;
    }

РЕДАКТИРОВАТЬ :

Я хочу один Init функция и несколько getInstance. Так что типичное использование это что-то вроде:

S::Init(5, 6.4);
foo(S::getInstance());
bar(S::getInstance());

Ответы [ 2 ]

0 голосов
/ 07 марта 2020

Вы можете просто сохранить параметры инициализации в статике. Пример:

class S {
public:
    static void Init(int i)
    {
        i_ = i;
        initialized_ = true;
    }

    static S& getInstance()
    {
        if (!initialized_) {
            throw SomeException;
        }
        static S instance(i_);
        return instance;
    }

private:
    S(int) { }

    static int i_;
    static bool initialized_;
};

Не забудьте на самом деле определить статику в файле реализации (.cpp):

int S::i_ = 0;
bool S::initialized_ = false;

Очевидно, что вы можете использовать и синглеты Мейера для них, но так как они встроенные типы и не зависящие от других данных, вы не сильно выиграете.

0 голосов
/ 07 марта 2020

Вы можете сделать что-то вроде этого:

class Singleton
{
private:
  static std::unique_ptr<Singleton>& getObject()
  {
    static std::unique_ptr<Singleton> instance;
    return instance;
  }

  Singleton(int foo);

public:
  static void Init(int foo)
  {
    auto& instance = getObject();
    if (instance) throw std::runtime_error("aleady inited");
    instance.reset(new Singleton(foo));
  }

  static Singleton& getInstance()
  {
    auto& instance = getObject();
    if (!instance) throw std::runtime_error("not inited");    
    return *instance;
  }
};

Обратите внимание, что это не потокобезопасно и будет иметь неопределенное поведение, если несколько потоков вызывают Init или поток вызывает getInstance, тогда как другой вызывает Init.

Если ваши параметры можно заменить аргументами шаблона, вы можете сделать это вместо этого:

template <int foo>
class SingletonImpl
{
private:
  SingletonImpl(int f);

public:
  static SingletonImpl<foo>& getInstance()
  {
    static SingletonImpl<foo> instance(foo);
    return instance;
  }
};

using Singleton = SingletonImpl<10>;

Лучшее решение, вероятно, состоит в том, чтобы разделить инициализацию и конструкцию:

class Singleton
{
private:
  std::atomic<bool> initialised;
  Singleton()
  : initialised(false)
  {
  }

  Singleton& instanceImpl()
  {
    static Singleton singleton;
    return singleton;
  }

public:
  void Init(int foo)
  {
    auto& instance = instanceImpl();
    if (instance.initialised) throw std::runtime_error("already inited");
    instance.initialised = true;
  }

  Singleton& getInstance()
  {
    auto& instance = instanceImpl();
    if (!instance.initialised) throw std::runtime_error("not inited");
    return instance;
  }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...