【问题标题】:C++ Inheritance : Calling virtual method when it has been overriddenC ++继承:在被覆盖时调用虚方法
【发布时间】:2015-10-07 18:47:41
【问题描述】:

我正在尝试构建一个 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_;
};

我正在创建一个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;
}

现在当我执行此操作时,为什么会收到错误消息 pure virtual function calledrun() 函数在 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

这里可能出了什么问题?

【问题讨论】:

  • 你在构造函数中调用虚函数start();。这就是这个错误的原因。
  • @Jagannath 这里定义得很好,不是问题。
  • 不,不是。至此,派生对象已经构建完成。

标签: c++ multithreading inheritance virtual-functions


【解决方案1】:

跟着,一步一步来:

1) 你构造对象。

2) 你执行以下代码:

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

父线程立即返回到main(),它立即退出并销毁您的对象。

这是你的错误:

  • 在父线程终止进程之前,您不能保证在start() 中启动的线程会到达对上述run() 的调用。子线程和父线程同时运行。

因此,每隔一段时间,父线程会在子线程启动之前销毁对象,并调用run()。

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

未定义的行为。

您每隔一段时间就会遇到的断言是这种未定义行为的一种可能结果。

【讨论】:

  • 基类的析构函数中的thread_.join()是否应该确保在线程运行之前对象不被销毁?
  • @subzero 这里有三个步骤: (A) 派生类析构函数 (B) 线程体执行 (C) 基类析构函数。 (A) 肯定发生在 (C) 之前。但是没有什么能阻止 (A) 在 (B) 之前 (C) 之前发生,这意味着在 run() 被调用之前,vtable 在 join() 被调用之前被展开。
  • @subzero ensure that the object is not destroyed 在 MT 编程中,控制对象的生命周期是您的工作。把它留给编译器总是会产生这样的问题。
  • 这是有道理的。谢谢!我该如何解决?我可以在派生类析构函数中放置一个thread_.join()。我想把所有的线程处理业务都封装在基类中?能做到吗?
  • @subzero:将join 调用放在stop 例程而不是析构函数中,并确保test 析构函数调用stop。或者,将service::run 设为 noop 虚函数而不是纯虚函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-25
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2018-07-26
  • 1970-01-01
相关资源
最近更新 更多