带参数的 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 单例,但由于它们是内置类型并且不依赖于其他数据,因此您不会真正获得太多。
是否可以定义带参数的 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 单例,但由于它们是内置类型并且不依赖于其他数据,因此您不会真正获得太多。