tags:

views:

135

answers:

6

I have an object that reads from a socket continuously like below:

void CSocketReader::ReadComplete ( )
{
 messageProcessor->ResponseReceived ( response );
 read ();
}

void CSocketReader::read()
{
 socket.read(response);
}

My problem is, depending on the response and on the protocol that I am executing the ResponseReceived method could lead to deletion of the CSocketReader object. When the ResponseReceived method returns the object the this pointer points to would have been deleted ( but for some reason not known to me the this pointer is not NULL even after its deleted!! ). Next the read method executes and the program crashes within read. How can I reliably detect that the method that's been executing on an object has been deleted.

Please help.

+8  A: 

What the value of the this pointer is after the object has been destructed is undefined in the C++ standard, so it should not be a surprise that this isn't NULL - C++ is not required to set it to NULL for you.

If the messageProcessor object destructs the CSocketReader object that has called it, then the design of your program is a little whacky. At least I would make the ResponseReceived function for example return a bool that is true if it has deleted the CSocketReader, so that you can do:

if (!messageProcessor->ResponseReceived(response)) {
    return;
}

Return immediately. But even this might not be safe; you shouldn't construct your program in such a way that code can be executed on a destructed object.

Jesper
+1 and generally, `delete` operation doesn't alter its operand.
Michael Krelin - hacker
code which runs on a destructed object is not a problem as long as it doesnt access any of it's member variables/properties. It can still access it's static membersvariables though
Toad
This is a neat solution. Except that if ResponseReceived method leads to a chain of method calls and the decision to delete the SocketReader object is made at the last call I would need to return bool all along the chain of calls.
ardsrk
@ardsrk - One solution I've seen is to have a "bool deleteMe" flag in the class. The last call (deeply nested subroutine) just sets that flag to true. The scheduler (which invokes the class) checks the flag, using code like "messageProcessor->ResponseReceived(response); /* the deleteMe flag may have been set to signal that this processor should be deleted */ if (messageProcessor->deleteMe) delete messageProcessor;"
ChrisW
@ChrisW - yeh this would have been even more easier to implement. Its not the messageProcessor I want to delete but the CSocketReader object. Anyway, I got your idea. Thanks.
ardsrk
+2  A: 

Deleting an object does not change pointers to that object. Implementing that would require that each object "knew" about all pointers to it, so it could set them all to NULL in its destructor. This would be a performance and memory nightmare, if it's even possible to implement. It would certainly cost a great deal of complexity, for a feature that is not always needed. C++ shies away from that type of design, preferring to not "force" you to pay for features you don't need.

One fix might be to not delete the object, but perhaps just set a flag "deleteMe", which can then be checked when you know you're no longer accessing the object.

unwind
A: 

You can not. There is no way to know that you are working on a deleted object. Whenever you try to access a member variable of that deleted object the behavior is undefined.

Naveen
A: 

delete'ing an object does not set its value to zero - it just runs the destructor(s), and frees the memory. If messageProcessor->ResponseReceived ( response ); function might delete the instance of the object that's calling that function, then you're in trouble - the value of the this pointer upon return will be unchanged (C++ won't rewrite the call stack for you), but you're now in undefined behaviour land. Moreover, other held pointers to this object will still point to the memory where the object lived, as there's no way to find all references and rewrite them - a pointer is just a stored value that's interpreted as an address.

The easiest solution is to have messageProcessor->ResponseReceived ( response ); return a flag indicating whether it should continue - if not, bail out immediately with return. The better solution is probably to re-design to avoid this situation.

Adam Wright
A: 

after deleting a pointer, it will not go automatically on null. You should set it explicitly to null if you want this.

when a method callsinto a class which doesn't exists anymore, nothing happens unless you use one of it's properties or fields. So code could potentially still run without problem.

So as the first few lines you could insert some code which checks if the this pointer is still a valid one. (You could check this for instance with a static hashmap which contains all the valid instance pointers). If you detect the this pointer is not valid anymore, exit the method

Toad
+4  A: 

How can I reliably detect that the method that's been executing on an object has been deleted.

You can't set a 'bool amDeleted' flag inside the object itself (because after it's deleted that flag/memory may be reused/overwritten by something else).

The only reliable way to do it (that I can think of) would be like this ...

class Foo
{
  //have a static set of all valid Foo instance pointers
  typedef std::set<Foo*> Set;
  static Set s_set;

public:
  Foo()
  {
    s_set.insert(this);
  }

  //ditto in every other Foo constructor, including the copy constructor

  ~Foo()
  {
    s_set.remove(this);
  }

private:
  static bool exists(Foo* foo)
  {
    return s_set.find(foo) != s_set.end();
  }
};

[... or a thread-safe Set if Foo is being constructed/run/destroyed off more than one thread].

ChrisW
That's just what I did, except that I used a static std::set instead of a static hashmap.
ChrisW
ah didn't read it correctly...I though you were also fiddling with the deleted flag...I'll remove my comment.
Toad
This solution worked without needing significant changes to the source. Thanks.
ardsrk