6
// 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()吗?我遇到了极其罕见的崩溃,不确定是否是因为这个逻辑中有问题。

4

5 回答 5

9

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

于 2016-06-17T08:01:59.127 回答
2

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

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

  1. 继承自 QObject

  2. 在类定义中使用 Q_OBJECT 宏

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

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

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

于 2016-06-17T02:01:11.713 回答
0

编辑:这个答案是对原始问题的回应,该问题没有使用QObjectclass 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`.

上述工作的原因是您class A在设置计时器时捕获了 shared_ptr ,并且计时器将保留它(否则它无法触发)。

如果您不喜欢或不能使用最近的 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);
于 2016-06-17T01:34:58.250 回答
0

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

这当然是在QTimer类中解决的,并且由计时器类的实例控制的所需行为将非静态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);

因此,不会由于与上下文对象一起释放的计时器而发生崩溃。

于 2016-06-17T03:34:58.797 回答
-1

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

class A : public QObject {
    QTimer t;
    A()  { connect(Signal-Slots); }
    ~A() { t.stop(); }
    fun() { t.start(10); }
    ...
};
于 2016-06-17T11:58:20.027 回答