带参数的 C++ Meyer 单例

C++ Meyer's Singleton with arguments

是否可以定义带参数的 Meyer 单例(如 this one)?

我知道可以使用 GOF 样式单例(如 here),

但我似乎无法让它与 Meyer 的单身人士一起工作:

// ...
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());

你可以这样做:

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;
  }
};

您可以只将初始化参数存储在静态中。示例:

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;

显然您也可以对这些使用 Meyer 单例,但由于它们是内置类型并且不依赖于其他数据,因此您不会真正获得太多。