user3522354
user3522354

Reputation: 223

singleton behaviour related query

I know this is very silly question about singleton pattern but still it is first choice of interviewer. Could you let me know in below code snippet.

(1) After deleting singleton object why still I am able to call show() method and it works fine.

delete obj;
obj=NULL;
obj->show();

(2) After creating obj1 object why i am not able to print the content of acquire_lock and release_lock function even print statment "one Time" will be printed once and if we increment counter i then instead of 2 it is printing 1 only, why?

Foo *obj1=MySingleton<Foo>::GetInstance();

(3) usage of unique_ptr with singleton object will have any negative implications.

code snippet:

#include <iostream>
#include <fstream>
#include <memory>
#include <string>

using namespace std;

static int i;

class Lock
{
public:
    Lock(){};
    ~Lock(){};

    void acquire_lock()
    {
        cout<<"aquired lock for class";
    }

    void release_lock()
    {
        cout<<"released lock for class";
    }

};

class Foo
{
public:
    void show()
    {
        cout<<"\ndone\n"; 
    }
};

template <class T>
class MySingleton
{
protected:

    MySingleton() {}

private:

    //holds one and only object of MySingleton
    static T* m_pOnlyOneInstance;
    MySingleton(const MySingleton <T> &) {};
    MySingleton <T> & operator=(const MySingleton <T> &) {};
    ~MySingleton() {};

public:

    static T * GetInstance();

    void foo()
    {
        cout<<"Mohan";
    }
};


template <class T>
T*  MySingleton<T>::GetInstance()
{
    Lock lock;
    if (m_pOnlyOneInstance == NULL)
    {  
        lock.acquire_lock();
        cout<<"one Time"<<endl;  
        i++; 
        if(m_pOnlyOneInstance == NULL)
        {
            m_pOnlyOneInstance = new T();
        }
        lock.release_lock();
    }  
    return m_pOnlyOneInstance;
}

template <class T> T* MySingleton<T> :: m_pOnlyOneInstance=NULL;

int main()
{
    //std::unique_ptr <Foo> obj (MySingleton<Foo>::GetInstance());
    Foo *obj=MySingleton<Foo>::GetInstance();    
    //obj->show();
    delete obj;
    obj=NULL;
    obj->show();
    cout<<"\ncalling again\n";
    Foo *obj1=MySingleton<Foo>::GetInstance();
    obj1->show();
    cout<<"i="<<i;  
    return 1;   
}

Note: lock related function are dummy implementation only.

Upvotes: 5

Views: 108

Answers (4)

user2997518
user2997518

Reputation: 852

This is not a proper way to delete the singleton object, you need to write below method in order to delete the instance and then execute your programme.

static void cleanup()
     {
        delete m_pOnlyOneInstance;
         m_pOnlyOneInstance= NULL;

     }

Here is the output :

aquired lock for classone Time released lock for class done

calling again aquired lock for classone Time released lock for class done i=2

Upvotes: 1

htc411
htc411

Reputation: 1

Your singleton class should have a private constructor and destructor. The destructor should handle any memory cleanup when the scope of the singleton ends, so there's no need to explicitly delete it. It could be unsafe to delete it when other objects are still accessing the singleton after the point of deletion. You could be getting an undefined behavior when you did "delete obj", and "obj=null" since you overloaded assignment operator and destructor are private.

Upvotes: 0

mooiamaduck
mooiamaduck

Reputation: 2156

  1. Keep in mind that obj->show() is equivalent to Foo::show(obj). Both expressions set this to the value of obj within the show member function. Now, what would setting this to NULL within show do? Nothing, because you never reference this.
  2. Well, think about the whole reason you would use the singleton pattern in the first place -- to initialize something at most one time. That "one time" print statement is in the code where the object gets instantiated, so naturally it doesn't get executed after the first time. Look at the logic of GetInstance. If an instance does not exist, it instantiates the class (messily... but it does work), and afterwards the instance exists. Otherwise, it does nothing.
  3. This question is very unclear, but what I assume you mean is "what are the negative implications of doing std::unique_ptr<Foo> obj = MySingleton<Foo>::GetInstance();?" As you can see from the reference for unique_ptr, its purpose is to take ownership of a dynamically allocated resource. This is definitely not supposed to happen when you're dealing with singleton objects. Because the resource (the singleton instance, in this case) is shared among any number of callers, the singleton class is the only one which should be managing the instance resource -- this is a fundamental invariant of the singleton pattern. If you use unique_ptr, as soon as obj goes out of scope, it will delete the instance automatically, regardless of whether your program references the now-freed instance elsewhere.

Upvotes: 2

Eelke
Eelke

Reputation: 22023

(1) The call would fail if it actually used obj either to perform the call or within the call.

First the call it self is to a non virtual function so the obj pointer is not needed to find the function. The compiler already figured out at compile time which function to call.

Second the function does not access any member variables of the class so while it does receive a this pointer that is NULL it actually never uses it.

BTW, it seems that this code tries to use the MySingleton template to turn other classes into singletons but it doesn't really as it doesn't prevent making copies or instantiating objects through other ways so it is no true singleton. The only thing it does is always return the same pointer.

Other BTW, the second call to MySingleton<Foo>::GetInstance() returns a copy of a pointer that you have previously deleted when you did delete obj. obj was set to NULL after the delete but the original pointer in the MySingleton template is still pointing to the deleted object so the second call to GetInstance will happily return the now invalid pointer.

Upvotes: 0

Related Questions