there are related questions like smart pointers + "this" considered harmful? but they do not handle my case. All these questions are about exposing a raw this pointer in case of reference counting smart pointers. However, my problem is not that I do expose this
but rather use it only in the method, but maybe for a longer period of time.
Consider the following code:
class X{
void foo(){...} //Performs some long running task
}
shared_ptr<X> x;
void bar(){
x->foo();
}
Okay, so some code calls the foo
method of object x. Consider that the only smart reference to the instance behind x is the one shared_ptr x. Now, foo performs some long running task invoking other functions and stuff.
Now, consider, while foo is running, another thread, a signal handler, or even a recursive call in foo
changes or clears the reference x
. This would trigger the deletion of the object. Now, the this
pointer on the call stack of foo
points to a deleted object. Further code execution in foo
will therefore produce unpredictable results.
How to avoid this? I mean, whenever being in the execution of a method of an object that is handled via reference counting, there is the danger that some code might clear the references to the object and the method call will fail or produce strange results. The problem is the semantics: The reference counting thinks that there is no more reference to the object and thus deletes it, but this is not true - there is still the this
reference, but sadly, it is not a smart pointer.
I know there is stuff like enable_shared_from_this
, but should I ALWAYS rewrite all methods of objects that could potentially be reference counted to first obtain a shared pointer from this
and then use that pointer, to be save from this problem? This would clutter all method code, and in addition, it might still fail: If an event clears x
after the call to foo has been made but before the first statement in the method (which obtains a shared instance) executes (maybe another thread), then things will fail again.
So the general question is:
When using any kind of smart pointers, how can I be safe during a method call to the managed object? How can I ensure that the this
pointer inside the method will not become invalid? Is rewriting all methods to use enable_shared_from_this
in their first statement a good solution?
Or is code that clears a reference while that reference is still on the call stack simply ill-formed? But if it is, then it is hard to write non-ill-formed code once multiple threads and complex recursive calls are used...