Reputation: 139
Assume I have a Singleton class. How can I prevent callers from being able to store the result of the call to getInstance() method?
I need this, since the instance of the singleton can be modified during execution and any stored instance in other classes will be invalidated. My solution would be to force all the callers to call getInstance() every time when they want to use the instance of the Singleton.
class Singleton
{
private:
static Singleton* instance;
private:
Singleton();
public:
static Singleton* getInstance();
};
Singleton* Singleton::instance = nullptr;
Singleton* Singleton::getInstance()
{
if (instance == nullptr)
{
instance = new Singleton();
}
return instance;
}
class A
{
private:
Singleton* m_singleton;
public:
A()
: m_singleton(Singleton::getInstance()) //This should not be possible
{
}
};
int main()
{
A a;
return 0;
}
How can I achieve this?
Upvotes: 1
Views: 528
Reputation: 1552
Use volatile to declare the singleton variable. This will force the compiler to always check for it
class Singleton
{
private:
static volatile Singleton* instance;
private:
Singleton();
public:
static volatile Singleton* getInstance();
};
Upvotes: 0
Reputation: 25536
You cannot. If your getInstance()
returns a pointer or reference, there is no way to prevent the result from being copied into some variable, the same way as you cannot prevent a result of type int
or double
from being copied.
You could, however, make the functions the singleton provides static:
class SomeSingleton
{
public:
static void foo();
private:
// deleting copy constructor and assignment operator...
static SomeSingleton* getInstance();
};
void SomeSingleton::foo()
{
SomeSingleton* instance = getInstance();
// use instance as you need to get the appropriate result
}
So you enforce usage like this:
SomeSingleton::foo();
Some might even consider it more comfortable to use than
SomeSingleton::getInstance().foo();
By the way: This aproach makes it possible to protect you from race conditions, too, if multi-threading is or gets an issue:
class SomeSingleton
{
public:
static void foo();
private:
static std::mutex mutex; // <- add a mutex!
static SomeSingleton* getInstance();
static void exchange();
};
void SomeSingleton::foo()
{
// this must be added whenever the singleton is used...
std::lock_guard<std::mutex> guard(mutex);
SomeSingleton* instance = getInstance();
// use instance as you need to get the appropriate result
}
void SomeSingleton::exchange()
{
// ... or the singleton instance is re-asigned
std::lock_guard<std::mutex> guard(mutex);
SomeSingleton* newInstance = new SomeSingleton();
delete instance;
instance = newInstance;
}
Upvotes: 2
Reputation: 844
First of all I wouldn't suggest using pointers for singletons. This ("Meyer Singleton") is a much better approach.
static SingletonDatabase &get() {
static SingletonDatabase db;
return db;
}
Also storing the singleton is kind of a bad idea, as with the storing you validate the initial idea / purpose behind the singleton: You are making copies, thus the singleton is not the "sole" instance of the class.
Anyway a great solution to your problem would be to use some kind of signal/slot system. (Qt / Boost library) Upon change you can emit the singal, which is then "caught" by all instances and the actualize the values.
Boost Signals / Slots Qt Signals Slots
I Hope this helps :)
Upvotes: 0
Reputation: 2119
My solution is a wrapper with overloaded ->
operator like in smart pointers which calls getInstance()
inside:
class Singleton {
friend SingletonWrapper;
private:
static Singleton * getInstance() {...}
public:
void foo() {}
};
class SingletonWrapper {
public:
Singleton * operator->() {
return Singleton::getInstance();
}
};
int main() {
SingletonWrapper w;
w->foo();
}
Upvotes: 1