Jump to content
  • Advertisement
Sign in to follow this  
AndiDog

OOP basic problem

This topic is 4335 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My objects contain the number of references which is 1 when created. The function AddRef increments this number (similar to Microsoft's COM model). I've got a Socket object and a Filter object. The socket object uses the filter and the filter uses the socket object.
// Simplified code!

#define DELETEOBJECT(obj) { if(obj->references-- == 1) delete obj; obj = 0; }

class Object
{
    Object() { references = 1; }

    int references;
};

class Filter : public Object
{
    Filter(Socket *s) { parent = s->AddRef(); }
    ~Filter() { DELETEOBJECT(parent); }

    Socket *parent;
};

class Socket : public Object
{
    ~Socket() { DELETEOBJECT(f); }

    SOCKET  handle; // used for network/Internet stuff
    Filter *f;

    void SetFilter(Filter *obj)
     {
     f = obj->AddRef();
     }
};

To explain it a bit: The filter stores a reference to the socket using AddRef(). The Socket::SetFilter() function stores a reference of the filter object.
// Simplified main function

int main()
{
    Socket *sock = new Socket; // 1 reference
    Filter *filter = new Filter; // 1 reference

    sock->SetFilter(filter); // filter now has 2 references...
    DELETEOBJECT(filter); // ... we don't use the filter in main(), so "delete" it: 1 reference remaining

    // do something

    // Here comes my problem: Socket has got 2 references
    DELETEOBJECT(sock)
}

The problem is, objects do only get deleted (= deconstructed) with references=1. But since the filter contains a reference to our socket object, the socket has references=2. So it is not deleted. In case we called "delete sock" directly, it would delete filter (and the socket reference with it) and everything was fine but that's not what it's supposed to be. Is there a solution and, does Microsoft's COM model have one for this problem???

Share this post


Link to post
Share on other sites
Advertisement
The only real "Solution" would be to put an assert() in the destructor and make sure the reference count is 1 (or 0, depending how your code works).

The only way COM handles it, is you don't create objects with new, you use some factory method. That causes the object not to be allocated in your applications heap, which causes an access violation if you try to delete the object manually, rather than Release()ing it.

Also, I'd personally change:
#define DELETEOBJECT(obj) { if(obj->references-- == 1) delete obj; obj = 0; }
To:
#define DELETEOBJECT(obj) { if(--obj->references == 0) delete obj; obj = 0; }
It just seems a bit tidier to me that way. Or, better - provide a Release() method rather than relying on a macro to do the job for you, and exposing data members as public.

Share this post


Link to post
Share on other sites
So it sounds like your problem is circular reference. Object A is holding the only pointer to object B and keeping it alive; object B is is holding the only pointer to object A and keeping it alive. This is a central problem with reference-counted pointers. It is solved by the idea of a "weak pointer", basically one which does not increment the reference counter. If one of the two pointers in the cycle was weak, both objects would be correctly deleted.

BTW, writing your own reference-counted object implementation to be robust and bug-free is surprisingly difficult. Using a really good premade one is almost certainly a better idea. (Specifically, you will be interested in shared_ptr and weak_ptr.)

Share this post


Link to post
Share on other sites
Alright no perfect solution out there, what a pity :)

@Evil Steve: As I wrote it is just simplified code, my real code is way more complex.

I'm gonna use the "weak pointer" solution which is quite o.k.

Thanks a lot

Share this post


Link to post
Share on other sites
The boost library has weak_ptr that you can use to break the circular dependencies.

Edit: Oh, I see that has alread been mentioned.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!