Determine if a method is pure virtual (c++)

1k views Asked by At

Is there a way to determine in c++ if a method is pure virtual at runtime? In fact the question is if there's a way to know if the destructor of a derived class has been already executed but the base class still alive.

This is my case (simplified):

class BaseClass{
private:
    class ThreadUtil *threadUtil;
public:
    Mutex mutex;
    ~BaseClass(){ 
              threadUtil->Terminate();
              MutexLocker ml(mutex);   // Avoid destruction during use
    }

    virtual Size size()=0;
};

class Derived:public BaseClass{
public:
    Size size()override{return Size(100,80);}   
};


class ThreadUtil{
private:
    bool terminate;
    BaseClass *owner;

public:
    void Run(){
        while(!terminate){
            if (!IS_OWNER_SIZE_FN_PURE_THAT_S_THE_QUESTION){
                MutexLocker ml(owner->mutex);
                DoSomething(owner->size());  // Runtime error if in the dtor of BaseClass 
            }
        }
    }
};

A "pure virtual function called" runtime error happens very sporadically (when DoSomething is invoked while ~BaseClass is being executed.

Terminating the thread +locking in the derived class is safe but I'd like to do it in the BaseClass (especially if there are many derived classes).

Is there a portable and clean (no flags around) way to implement this?... or what's wrong with the above design?

Edit:--------------------

As some have noted, the pure virtual is not the real problem. It is entering the destructor of the base class with the thread still running. The actual question maybe should be, "is there a way to have a pre-destructor method in a base class?"

In Is there any automated way to implement post-constructor and pre-destructor virtual method calls? pointed by Jeremy Friesner, there's an interesting idea:

  • Making the destructor of the base and derived classes protected so delete can't be invoked.
  • Making the destructor of BaseClass virtual.
  • Implementing in the base class Delete() that first terminates the thread and then calls the destructor (being virtual derived destructors are called)
2

There are 2 answers

1
Jeremy Friesner On

You're barking up the wrong tree here -- in a correct C++ program, it's impossible to call a pure virtual function (because the attempt to call it will be flagged as an error by the compiler), so there is no need to determine at runtime whether a function is pure-virtual or not.

The reason you're getting the "pure virtual function called" error sometimes is because your program is buggy -- in particular, it's suffering from a race condition where your Run() method is calling methods on an object that is in the process of being destroyed.

What you need to do here is make sure the thread has exited (by asking the thread to exit, and then calling pthread_join() (or something other API that is equivalent to that, that will block until the thread has 100% gone away) before destroying any objects that the thread might access while running. Only start your cleanup after the the thread is dead, and that way you will avoid the race condition and therefore the errors/crashing.

Note that it won't work to place the pthread_join() call in your BaseClass's destructor method, because by the time your BaseClass destructor function runs, the object's subclasses-layers have already been destroyed. You need to clean up the thread before deleting the object of which BaseClass is the superclass. (granted it's a bit awkward to automate that sequence in C++, since AFAICT you have to make sure the caller calls the pre-delete thread-shutdown function manually; in particular there's no easy/automatic/transparent way to automate the generation of the pre-destructor thread-shutdown code)

0
Slava On

Is there a portable and clean (no flags around) way to implement this?... or what's wrong with the above design?

Portable and clean way is to prevent object being destroyed before thread is terminates. That can be achieved by class TheradUtil to own or share ownership to BaseClass through a smart pointer of proper type.