This is a made-up scenario based off a real issue. If I have a base class:
class Vehicle
{
public:
void run() { incrementStuff(); }
virtual void incrementStuff() { }
};
And a derived class:
class Car : public Vehicle
{
public:
Car() : Vehicle() { stuff = new StuffClass(); }
~Car() { delete stuff; stuff = NULL; }
virtual void incrementStuff() { if (stuff != NULL) stuff->increment(); }
protected:
StuffClass* stuff;
};
Then say I have a thread which calls Vehicle::run() periodically. I have another thread that eventually deletes the pointer to car. The order of destruction will cause car to be deleted first, then vehicle.
What happens if the thread (living in the Vehicle object) calls the incrementStuff function AFTER the destructor has run in car (but obviously before vehicle has been destructed)? Will the Car::incrementStuff be executed and try to dereference an already deleted pointer? Or will the Vehicle::incrementStuff be called which is safe and does nothing?
Assume that the thread cannot call into Car::incrementStuff while Car::~Car() is running (this is prevented by a mutex).
This code has been refactored to avoid this, but I was just wondering if anyone can shed some light onto how this works, or if it is just plain undefined behavior?
More generally, what happens if I try to call Car::incrementStuff after Car has been destructed but before Vehicle has been? Will the NULL check work, or is that memory already deallocated and could be used by anything now? Or is that memory not 'freed' until the base object has been destructed?