1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Deleting a singleton

Discussion in 'C++' started by pyr0man, Oct 24, 2009.

  1. pyr0man

    pyr0man New Member

    Joined:
    Oct 24, 2009
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    0
    I'm an IT student working on a system design project. It's a hierarchy of classes all inheriting from a base-class called Object (so we can use polymorphism). As part of the specs, we have a NullObject class that needs to be implemented as a singleton.

    The NullObject is used frequently in containers and is treated just like other Objects. This includes some deleting, which is where the problems start.

    I overloaded the delete operator to only delete the instance when a reference count is zero. It works fine if you only call delete as an operator, as in
    Object *obj = NullObject::getInstance(); //obj points to instance
    obj->delete(obj);
    but if you just call it as
    delete obj;
    it first calls the destructor. The memory isn't deallocated, but the NullObject loses its "objectness". If I have another pointer to the instance (which I have), it is no longer treated as a NullObject. (In my program, it gets treated as an Object, which is abstract - no good).

    Most singleton tutorials simply say that singletons don't usually get deleted in the middle of programs and don't address the issue at all. Is there a way to stop the destructor from being called? Or should I change all the deletes to operator deletes (overloaded for Object)?
     
  2. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,012
    Likes Received:
    203
    Trophy Points:
    0
    Occupation:
    Senior Support Engineer
    Location:
    England
    How do you know the memory isn't deallocated?
    What exactly do you mean by "NullObject loses its 'objectness'"?
    Could you post the code for NullObject?
     
  3. pyr0man

    pyr0man New Member

    Joined:
    Oct 24, 2009
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    0
    The overloaded delete operator for NullObject:

    void NullObject::eek:perator delete (void* p)
    {
    if (count != 0) // count is a static int that gets ++-ed in getInstance()
    count--;

    if (count == 0)
    {
    ::eek:perator delete(p);
    }
    }

    Because the program deals with most classes as Objects (ie the base-class), delete is also overloaded for Object like this:

    void Object::eek:perator delete (void* a)
    {
    Object* p = reinterpret_cast<Object*>(a);
    if ((p)->isNull()) // always returns true for NullObject, typeid for other
    {
    NullObject* no = dynamic_cast<NullObject*>(p);
    operator delete(no);
    }
    else
    ::eek:perator delete (a);
    }

    Basically, it checks if the Object is a NullObject. If it is, it calls the overloaded delete. Else, it calls the global delete.

    As I said before, it works when you don't just call delete, but call it as an operator. That's why I think the memory isn't deallocated. I can have multiple NullObjects, all pointing to the same instance, and when I delete one (using the long way) the others work fine.

    However, when I just go
    delete aNullObject;
    c++ automatically calls the destructor too (I can't remember the order in which things get called). That's where it falls apart. The NullObject is no longer seen as a NullObject (isNull() returns false).
     
  4. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,012
    Likes Received:
    203
    Trophy Points:
    0
    Occupation:
    Senior Support Engineer
    Location:
    England
    I meant the whole code for NullObject, and you should use code blocks to avoid smilies and to preserve formatting.
    Have you tried making the destructor private, if you don't want people to be able to delete it?
    Then to delete the object people will be forced to call the appropriate function.
     
  5. pyr0man

    pyr0man New Member

    Joined:
    Oct 24, 2009
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    0
    Oops, how do i do code blocks, same as dreamincode
    Code:
    ...
    ?

    Tried making the destructor private, but for some reason that did nothing. Maybe because all objects are seen as base-class Object, and delete is called from there, so it's legit?

    Either way, I'm looking for a way for delete to work, even on the singleton, but I guess it doesn't work that way.

    I'll post everything, but am running swiftly out of time, so I adapted it to a less cool but almost working version. Still, it's quite an interesting problem (to me at least)

    NullObject.h
    Code:
    #ifndef NULLOBJECT_H
    #define NULLOBJECT_H
    
    #include "Object.h"
    #include <iostream>
    
    using namespace std;
    
    /**
    * An Object that represents 'null'.
    */
    class NullObject: public Object // has Singleton been implemented correctly?
    {
    	private:
    		static NullObject* instance;
    		static unsigned count;
    		
    	protected:
    		~NullObject() {}
    		NullObject() {}
    		NullObject(const NullObject&);
    		NullObject& operator = (const NullObject&);
    		virtual int compareTo(const Object&) const;
    	public:
    
    		static NullObject* getInstance()
    		{
    			if (instance == 0 && count == 0)
    				instance = new NullObject();
    			count++;
    			return instance;
    		}
    		
    		void operator delete (void*);
    		
    		
    		virtual bool isNull() const;
    		virtual void print(ostream& = cout) const;
    		virtual Object* clone() const;
    		virtual Object& assignment (const Object&);
    };
    
    #endif
    
    NullObject.C:
    Code:
    #include "NullObject.h"
    #include <typeinfo>
    
    NullObject* NullObject::instance =NULL;
    unsigned NullObject::count = 0;
    
    /**
    * Checks if 'other' is another NullObject, and then compares accordingly.
    */
    int NullObject::compareTo(const Object& other) const
    {
    	if (typeid (NullObject) == typeid (other))
    		return 0;
    	else
    		throw ("incompatible_type_exception"); // the two types need to be identical
    }
    		
    void NullObject::operator delete (void* p)
    {
    	if (count != 0)
    		count--;
    
    	if (count == 0)
    	{
    		::operator delete(p);
    	}
    }
    
    NullObject::NullObject(const NullObject& other)
    {
    	instance = other.instance;
    }
    
    NullObject& NullObject::operator = (const NullObject& other)
    {
    	instance = other.instance;
    	return *instance;
    }
    
    bool NullObject::isNull () const
    {
    	return true;
    }
    
    void NullObject::print (ostream& out) const
    {
    	out << "NullObject" << endl;
    }
    
    Object* NullObject::clone () const
    {
    	return new NullObject();
    }
    
    Object& NullObject::assignment (const Object& other)
    {
    	if (typeid(other) == typeid(NullObject))
    	{
    		return (*this);
    	}
    	else
    		throw ("incompatible_type_exception");
    }
    
     
  6. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,012
    Likes Received:
    203
    Trophy Points:
    0
    Occupation:
    Senior Support Engineer
    Location:
    England
    I don't know how dreamincode works, but how to post code is outlined where you post a new thread: immediately below the title box there is the text "Before proceeding, please make sure you are aware of the Community Guidelines and you have read the Hints before you make a post thread."

    When posting to a forum you're new to, you should ALWAYS look for and read such things. It's not all legal mumbo jumbo, you get posting guidelines too. Code tags are number 7 of "Hints before you make a post", and it's called "hints ***BEFORE*** you make a post" for a good reason.
     

Share This Page