C++继承:在重写时调用虚方法

ssb*_*ssb 7 c++ inheritance multithreading virtual-functions

我试图在一个单独的线程中构建一个service可以运行(即执行它的run()函数)的对象.这是服务对象

#include <boost/noncopyable.hpp>
#include <atomic>
#include <thread>
#include <iostream>

class service : public boost::noncopyable {
 public:
  service() : stop_(false), started_(false) { }

  virtual ~service() {
    stop();
    if (thread_.joinable()) {
      thread_.join();
    }
  }

  virtual void stop() { stop_ = true; }

  virtual void start() {
    if (started_.load() == false) {
      started_ = true;
      thread_ = std::thread([&] () {
        run();
      });
    }
  }

 protected:
  virtual void run() = 0;

  std::atomic<bool> stop_;

  std::atomic<bool> started_;

  std::thread thread_;
};
Run Code Online (Sandbox Code Playgroud)

我正在创建一个test继承自这个抽象类的类,并在main()函数中调用

class test : public service {
 public:
  test() : service() {
    std::cout<< "CTOR" << std::endl;
    start();
  }

  ~test() {
    std::cout<< "DTOR" << std::endl;
  }

 protected:
  void run() override {
    std::cout << "HELLO WORLD" <<std::endl;
  }
};


int main() {
  test test1;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在,当我执行此操作时,为什么会出现错误pure virtual function called?该run()功能在test课堂上被明确覆盖.更糟糕的是它有时会正确运行吗?

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

$ ./a.out
CTOR
DTOR
HELLO WORLD

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception
Run Code Online (Sandbox Code Playgroud)

这可能会出错?

Sam*_*hik 10

跟着,一步一步:

1)构造对象.

2)您执行以下代码:

if (started_.load() == false) {
  started_ = true;
  thread_ = std::thread([&] () {
    run();
  });
}
Run Code Online (Sandbox Code Playgroud)

父线程立即返回到main()立即退出的位置并销毁您的对象.

这是你的错误:

  • 在父线程终止进程之前,无法保证启动的线程start()将在run()上面调用.子线程和父线程同时运行.

因此,每隔一段时间,父线程将在子线程进入齿轮之前销毁对象,并调用run().

此时,其run()方法被调用的对象已被销毁.

未定义的行为.

你每次偶尔会遇到的断言是这种未定义行为的一种可能结果.

  • @subzero这里有三个步骤:(A)派生类析构函数(B)执行的线程体(C)基类析构函数.(A)肯定发生在(C)之前.但是没有什么能阻止(A)在(C)之前(B)发生,这意味着在调用`join()`之前调用`run()之前,vtable是展开的. (2认同)