如何在Qt中删除绑定对象



有两个类:WidgetWorker。这是一个原理图代码。

class Widget
{
    Worker *m_worker;
    QTextEdit *m_edit;
public:
    Widget():m_edit(new QTextEdit){}
   ~Widget()
   {
       m_worker->ShouldStop = true;
       delete *m_worker;
   }
   void doWork()
   {
      m_worker = new Worker;
      if (!worker->doWork())
          m_edit->setText("failed");
   }
}
class Worker
{
    Worker() : ShouldStop(false){}
public:
    bool ShouldStop;
    bool doWork()
    {
        while(true && !ShouldStop)
        {
            QThread::sleep(1);
            QApplication::processEvents();
        }
        //consider the work undone if a stop was forced
        if (ShouldStop)
            return false;
    }
}

调用WidgetdoWork()后,在WorkerdoWork()方法中执行循环。然后关闭小部件,并在对processEvents()的一次调用中调用其析构函数。然后执行返回到WorkerdoWork()。它现在检查ShouldStop,并返回到WidgetdoWork(),并尝试向m_edit添加一些东西。然而,Widget对象已经死亡。

问题:

  1. 如何干净地删除Worker ?
  2. 避免这种相互作用的最佳设计是什么?

理想情况下,工作线程应该通过信号和插槽机制返回数据,而不是直接访问原始对象。实际上,创建一个线程并避免调用QApplication::processEvents()是避免这个问题的第一种方法。

另外,当你想在一个新线程中启动一个worker时,你应该考虑使用这样的设计。您可以创建一个泛型的QThread并为其分配一个QObject,而不是创建QThread的子类,如下所示:

Worker *worker = new Worker;
QThread *workerThread = new QThread(this);
connect(workerThread, &QThread::started, worker, &Worker::doWork);
connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
worker->moveToThread(workerThread);
// Starts an event loop, and emits workerThread->started()
workerThread->start();

如果您正在使用Qt 5,请考虑围绕此模式重构您的代码。

@Alex的回答绝对是q2的选择。他只是忘了提到如何进行删除(q1)。假设Widget创建了对象workerThread,那么这是必要的:

 ~Widget(){
   if(workerThread->isRunning()){
         workerThread->terminate(); <--- this line, right there
         workerThread->wait(): 
   }
 ...
 }

为什么?因为删除QThread只是删除线程对象,而不会停止线程的运行,并且可能导致应用程序崩溃。注意,如果使用

connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);

如Alex所说的

,那么在调用terminate之后访问worker是不安全的,因为它会触发finished()信号,执行worker->deleteLater,最终删除worker

你可以让Widget使用一个信号来通知Widget的所有者为Widget启动Worker。

Owner同时拥有Widget和Worker。Widget告诉Owner某事被触发了,而Owner负责决定Worker的doWork()是否是正确的响应,并负责管理Worker和Widget的生命周期。Worker和Widget彼此不知道对方,但是Owner可能会将它们的一些信号和插槽连接在一起。

相关内容

  • 没有找到相关文章

最新更新