Reputation: 7162
Is it possible to define a Meyer's singleton (like this one) with arguments?
I know it is possible with the GOF style singleton (like here),
but I can't seem to make it work with Meyer's singletons:
// ...
public:
static S& getInstance()
{
static S instance; // no way to pass arguments here ...
return instance;
}
EDIT:
I want a single Init
function, and multiple getInstance
.
So a typical usage is something like:
S::Init(5, 6.4);
foo(S::getInstance());
bar(S::getInstance());
Upvotes: 5
Views: 1989
Reputation: 51910
You can just store the initialization parameters in statics. Example:
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_;
};
Remember to actually define the statics in the implementation (.cpp
) file:
int S::i_ = 0;
bool S::initialized_ = false;
Obviously you could use Meyer singletons as well for these, but since they're built-in types and do not depend on other data, you wouldn't really gain much.
Upvotes: 3
Reputation: 36488
You could do something like this:
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;
}
};
Note that this isn't thread safe and will have undefined behaviour if multiple threads call Init
or a thread calls getInstance
whilst another is calling Init
.
If your parameters could be replaced by template arguments then you could do it this way instead:
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>;
The best solution is probably to separate initialisation and construction:
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;
}
};
Upvotes: -1