是否存在使用std :: set_terminate无法捕获C ++纯虚函数调用的情况?

时间:2014-04-16 13:47:45

标签: c++ linux

在Linux服务器上运行的可执行文件的深处,有一个C ++纯虚函数调用。它导致服务器崩溃,不留任何程序跟踪数据,没有堆栈跟踪,也没有核心转储。只保留一些日志文件。这几乎肯定是由一生的问题引起的,我很清楚它在哪里发生,但我想要证明。我试图通过使用std::set_terminate来设置在调用terminate时运行的处理程序来解决这种情况。这适用于测试。例如,如果我使用:

进行纯虚拟呼叫
class Base {
public:
    Base() {}
    virtual ~Base(){}
    virtual void foo() = 0;
};

class Derived: public Base {
public:
    Derived(): n_(0) {}
    ~Derived(){}
    void foo() {
            n_ = 1;
    }
private:
    int n_;
};              

然后

Base* p = new Derived();
Base* p1 = p;
p->~Base();
p1->foo();

处理程序工作并生成跟踪数据,堆栈跟踪和核心转储。运行时系统打印

  

名为

的纯虚方法

进行此测试。

代码中没有其他对set_terminate的调用。测试在服务器启动并运行时完成,因此任何后续调用都可能已经发生过,如果他们要去的话。但是,在实际的服务器中,捕获纯虚拟调用。我能想到的唯一可能导致这种情况的是调用在我之后设置终止处理程序。有没有其他方法可以避免我的终止处理程序?

1 个答案:

答案 0 :(得分:0)

实际上,如果您有未定义的行为,对执行环境或编译的二进制文件的任何更改都可能导致您的代码以不同的方式行为异常。

对于更改的优化和调试标志,这是特别明显的,但看似无害的代码更改也预先触发了这一点。

接下来,你的错误可能是heisenbug,意思是与时序/多线程相关吗?

此外,如果构造/销毁中不需要虚拟表,则编译器可能会完全省略虚拟表,并且实际上并未创建确切类型的对象。
因此,尽管析构函数已经运行,但您对foo的调用可能同样崩溃或调用derived::foo