c++ - 虚函数和 boost 绑定(bind)奇怪的行为

标签 c++ boost

我在 Linux 下写的一段代码中看到了一个奇怪的行为,我想分享一下,看看是否有人知道原因。 我有一个基类和一个派生类。在基类中我定义了一个虚方法,在派生类中我重新定义了那个方法,具有相同的签名。然后我使用boost bind来启动一个线程。这是示例代码:

Class Base {
public:
    virtual void DoSomething();
    virtual void Init() = 0;
    ...
}

Class Derived : public Base {
public:
    void DoSomething();
    void Init();
    ...
}

在 Derived 类的 Init 方法中我这样做了:

 boost::thread *t = new boost::thread(boost::bind(&Base::DoSomething, this));

基类的 DoSomething 方法做了它应该做的事情,而派生类的相同方法是一个空方法,错误地留在那里。现在,在运行上面的代码时,大多数时候 Base 类的 DoSomething 是在线程中执行的,因此应用程序运行良好,但有时却无法运行。经过一些调试后,我注意到上面的错误,删除派生类的 DoSomething 解决了这个问题。在 Debug模式下使用 Eclipse 似乎总是调用派生类的 DoSomething 方法,而从控制台运行应用程序在大多数情况下都有效,但并非总是如此。这种行为有原因吗?我的意思是,为什么有时绑定(bind)函数使用基类方法,有时使用派生类的相同方法?

提前致谢

编辑以回应@pmr

很难展示一个完整的工作示例,我将尝试展示一些类是如何使用的。

首先我实例化一个 Derived 对象,然后在 init 函数中我使用上面显示的初始化代码启动线程。 DoSomething 有一个在 vector 上迭代的 while 循环,但这不是我认为的重点。

void Derived::Init()
{
    ...
    boost::thread *t = new boost::thread(boost::bind(&Base::DoSomething, this));
}

void Base::DoSomething()
{
    while(true) {
        ...
    }
}

void Derived::DoSomething()
{
}

正如您在这段代码中看到的,Derived DoSomething 方法是空的,所以有时我没有看到任何处理,而是发生在 Base DoSomething 函数中。

最佳答案

这是一个疯狂的猜测:你用来启动线程的对象实际上被销毁了!由于虚函数的绑定(bind)在销毁期间发生变化(当对象被销毁时,所有虚函数都解析为就好像所使用的对象是当前正在销毁的类的一种类型)。为此,通常将“vtable 指针”重置为指向合适的“虚函数表”。一旦基地被摧毁,就没有必要进一步摧毁物体。

这与您对随机行为的解释非常吻合:有时父线程执行得足够快,足以到达基类构造函数,有时却没有。在使用 Debug模式编译时,父线程显然在销毁对象之前一直花费很长时间。您关于在许多情况下一切正常的说法并没有真正破坏该形象:通常有错误的代码看起来好像可以正常工作,尽管在更仔细地检查时它实际上显示出不稳定的行为。

关于c++ - 虚函数和 boost 绑定(bind)奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8955289/

相关文章:

c++ - 从 linux 终端使用外部库编译 c++ 文件

c++ - boost asio 的链接器问题

python - 找不到 boost 或 python

c++ - 函数调用参数总是一个新对象吗?

c++ - 如何在 C++ 中一次性生成不同的随机数?

c++ - 从 rtti 中剥离类名

具有多重继承的 C++ 类型转换

c++ - boost::bind & boost::function 指向重载或模板化成员函数的指针

c++ - 我可以从同一个文件夹为 mingw 和 windows 构建 boost 吗?

c++ - 在编译时指定静态和动态大小