I'm working on an application that has the following problem. Basically there are a lot of object that implicitly might destroy themselves.
void Foo::func()
{
...
Bar b;
b.func2();
}
Here the func2
might destroy the foo
object calling it. Since it is not very obvious that this might happen I would like to make sure that no member variables of the foo
object can be accessed after this call, since I cannot guarantee they are still valid. If this call to b is the last call I am perfectly fine, but since I am not the only one working on this project and the destruction is not obvious I would like to implement something to block usage this
after these calls. Is there a way to implement this without completely refactoring the current design (since it is use extensively thoughout the project)?
Some background info:
It is a Qt UI application that uses QML to keep track of a stack of "screens" (a screen is a QML + its corresponding C++ model). The Bar
class in my example is the 'stack manager' which controls the lifetime of the screens. It is a singleton (I know). The Foo
class is a C++ model for a specific QML. The function Foo::func()
is a function that can be called either from user input in the QML or another system event. The function normally processes the event, but occasionaly it can tell the screen manager to delete one or more screen(s), which in turn deletes the model corresponding to that screen (which might be the calling model).
The this
pointer can't be blocked. As with all raw pointers, you must be sure that it's valid before dereferencing it.
But that's not all: what if the Foo
that was calling fun2()
was a local object of automatic storage duration ?
delete
the object instead of just destroying it, it would be undefined behavior in any case.One way out of this situation would be to create all the Foo
and Bar
objects using factories (making sure that the constructor is not public), and let these factories return shared_ptr
.
This has the advantage that if an object is not used anymore, it will destroy itself. That's a lot cleaner than managing destruction manually.
You'd face however several challenges:
shared_ptr
(if the pointer must ensure the object is still alive) and when to use weak_ptr
(i.e. pointer that doesn't contribute to keeping objects alive).Another alternative would be to use states to make the difference between an active object that can be used, and a deceased objet that shall no longer be used. So instead of deleting the object, you'd call a state change function that would clean/reset the object.
This can be implemented :
The advantage of this approach is that the state change function will be very simple (most of the things you have currently in the destructor, but avoiding they could be done by accident a second time) and make the tricky part very visible.
The difficulty will be to ensure that the deceased objects are cleaned for good. So you need to address the ownership issue that was already mentioned earlier, and make sure the objects are not deleted in the middle of their actions.