Vahagn
Vahagn

Reputation: 139

How to prevent a caller of a method from storing the result in C++

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

Answers (4)

Damien
Damien

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

Aconcagua
Aconcagua

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

Ph03n1x
Ph03n1x

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

Zefick
Zefick

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

Related Questions