繁体   English   中英

删除对象后触发QTimer :: SingleShot

[英]QTimer::SingleShot fired after object is deleted

// Example class
class A : public QObject
{
   Q_OBJECT
   void fun() {
       Timer::SingleShot(10, timerSlot); //rough code
   }
   public slot:
   void timerSlot();
}

auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a deleted

在这种情况下删除a并触发计时器后,它会执行timerSlot()吗? 我得到了一次非常罕见的崩溃,并且不确定是不是因为这个逻辑中有些可疑。

即使计时器触发,也不会触发插槽。 ~QObject状态的文档: 所有 ~QObject 对象的信号都会自动断开,并且从事件队列中删除对象的任何待处理的已发布事件。 您可以同时触发A::timerSlot并删除A的唯一方法是使用线程。

在删除对象的信号和插槽之前,您没有义务断开它。

QObject析构函数将为您清理过时的信号槽连接 ,只要您:

  1. 从QObject继承

  2. 在类定义中使用Q_OBJECT宏

遵循这些约定可确保对象在删除时发出destroyed()信号。 这实际上是Qt的信号和插槽系统用来清理悬空引用的内容。

如果您想添加一些调试代码来跟踪对象生命周期,您可以自己监听destroyed()信号。

(根据您使用的Qt / moc的特定版本,很可能使用非QObject使用插槽的代码,或者在其标头中没有Q_OBJECT的QObject派生类仍将编译但导致timerSlot()在运行时在垃圾指针上调用的方法。)

编辑:这个答案是对原始问题的回应,该问题没有使用QObject但是class A作为一个独立的类继承了什么。 这个问题后来被编辑,使得这个答案已经过时,但是我将把它留在这里,以显示如果不使用QObject将需要什么。


你能做到这一点的唯一方法就是让对象保持活着直到定时器被触发。 例如:

class A : enable_shared_from_this<A> {
   void fun() {
       QTimer::singleShot(10, bind(&A::timerSlot, shared_from_this()));
   }
public:
   void timerSlot();
}

auto a = SharedPointer<A>(new A);
a->fun();
a->reset(); // a goes out of scope, but its referent is kept alive by the `QTimer`.

上面的工作原理是你在设置定时器时将shared_ptr捕获到class A ,并且定时器将保持在它上面(否则它不能触发)。

如果您不喜欢或不能使用最新的C ++功能或Boost:

struct Functor {
    Functor(SharedPointer<A> a) : _a(a) {}
    void operator() { a->timerSlot(); }
    SharedPointer _a;
};

class A {
   void fun(shared_ptr<A> self) {
       QTimer::singleShot(10, Functor(self));
   }
public:
   void timerSlot();
}

auto a = SharedPointer<A>(new A);
a->fun(a);

由于计时器超出了对象范围而我只需要触发一次,因此我遇到了极其罕见的崩溃。 我使用的是QTimer :: singleShot,它是静态方法,不属于QTimer对象的实例,我将使用它触发信号的上下文释放它。

这当然是在QTimer类中解决的,并且期望的行为由timer类的实例控制,非静态QTimer :: singleShot属性设置为true。

// declaration
   QScopedPointer<QTimer> m_timer;

protected slots:
   void onTimeout();

// usage
m_timer.reset(new QTimer);
m_timer->setSingleShot(true);
QObject::connect(m_timer.data(), SIGNAL(timeout()), this, SLOT(onTimeout()));
m_timer->start(requiredTimeout);

因此,由于上下文对象释放了计时器,因此不会发生崩溃。

为了达到确定性,您可以自己停止计时器:

class A : public QObject {
    QTimer t;
    A()  { connect(Signal-Slots); }
    ~A() { t.stop(); }
    fun() { t.start(10); }
    ...
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM