确定方法是否是纯虚拟的(c ++)

时间:2017-01-09 18:13:30

标签: c++ destructor pure-virtual

有没有办法在c ++中确定方法在运行时是否为纯虚拟?实际上问题是,是否有办法知道派生类的析构函数是否已经执行但基类仍然存活。

这是我的情况(简化):

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 
            }
        }
    }
};

“纯虚函数称为”运行时错误非常偶然发生(当执行~BaseClass时调用DoSomething。

在派生类中终止线程+锁定是安全的,但我想在BaseClass中执行它(特别是如果有许多派生类)。

是否有可移植且干净(没有标记)的方式来实现这个?...或者上述设计有什么问题?

修改:--------------------

有些人已经注意到,纯虚拟并不是真正的问题。它正在进入基类的析构函数,线程仍在运行。实际的问题可能应该是,“有没有办法在基类中使用析构前方法?

在杰里米弗里斯纳指出的Is there any automated way to implement post-constructor and pre-destructor virtual method calls?中,有一个有趣的想法:

  • 使基类和派生类的析构函数受到保护,因此无法调用delete。
  • 使BaseClass的析构函数变为虚拟。
  • 在基类中实现Delete()首先终止线程,然后调用析构函数(调用虚拟派生析构函数)

2 个答案:

答案 0 :(得分:7)

你在这里咆哮错误的树 - 在正确的C ++程序中,不可能调用纯虚函数(因为调用它的尝试将被编译器标记为错误),所以没有需要在运行时确定函数是否为纯虚函数。

你得到“纯虚函数调用”错误的原因有时是因为你的程序有问题 - 特别是,它遇到了一个竞争条件,你的Run()方法正在调用一个对象上的方法被摧毁的过程。

你需要做的是确保线程已经退出(通过要求线程退出,然后调用pthread_join()(或者其他类似的API),这将阻塞直到线程100%消失了之前销毁线程可能在运行时访问的任何对象。只有在线程死亡后才开始清理,这样你就可以避免竞争条件和因此错误/崩溃。

请注意,将pthread_join()调用放在BaseClass的析构函数方法中是行不通的,因为在BaseClass析构函数运行时,对象的子类层已经被销毁。在删除BaseClass为超类的对象之前,需要清理线程。 (授予它在C ++中自动执行该序列有点尴尬,因为AFAICT你必须确保调用者手动调用预删除线程关闭函数;特别是no easy/automatic/transparent way to automate the generation of the pre-destructor thread-shutdown code

答案 1 :(得分:0)

  

是否有可移植且干净(没有标记)的方式来实现这个?...或者上述设计有什么问题?

便携和干净的方法是在线程终止之前防止对象被破坏。这可以通过类TheradUtil来实现,通过适当类型的智能指针拥有或共享BaseClass的所有权。