2016-06-17 34 views
3
//Example class 
class A : pubic 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()嗎?我正在發生一次極其罕見的事故,並且不確定是否因爲這種邏輯中的某些事情而發生。QTimer :: SingleShot在對象被刪除後觸發

+0

請刪除「粗碼」,並添加*確切*代碼在那裏。在一個測試案例中,魔鬼在細節中...... – peppe

回答

8

即使定時器啓動,它也不會觸發插槽。 ~QObject狀態的文檔:All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue.如果您使用線程,則同時觸發A::timerSlot和刪除A的唯一方法是使用線程。

+0

當OP公佈這個問題時,'QObject'不在那裏。現在它是。鑑於新的要求,我喜歡這個答案。 –

+0

你寫道:「如果你使用線程,你可以同時觸發A :: timerSlot和刪除A.你能證明這一點嗎? 「同時」是什麼意思?你是說如果他利用數據競賽? –

+0

@ JohannesSchaub-litb正是如此。這是不好的設計,當然不應該這樣做,但這是一種可能性。 – thuga

0

編輯:這個答案是迴應原來的問題,沒有使用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); 
+0

所以,主要問題是,如果'a'超出範圍,計時器會觸發(根據我的代碼庫)?或QTimer會失效? – PnotNP

+0

除非您銷燬或禁用計時器,否則計時器會啓動。當它觸發時,在你的原始代碼中,會導致未定義的行爲,因爲'this'指針將是無效的(free-after-free)。 –

+0

只需注意:「沒有最近的C++特性」部分使用'std :: shared_ptr',它是在C++ 11中引入的。 –

2

您沒有義務刪除之前斷開對象的信號和槽。從QObject的

  1. 繼承

  2. Use the Q_OBJECT macro in your class definition

以下這些:

QObject的析構函數會收拾你過時的信號槽連接,只要你約定可確保您的對象在刪除時發出destroyed()信號。這實際上是Qt的信號和插槽系統用來清除懸掛引用的東西。

如果您想添加一些調試代碼來跟蹤對象生命週期,您可以自己聆聽destroyed()信號。 (根據您使用的Qt/moc的特定版本,使用插槽的非QObject代碼或其頭中沒有Q_OBJECT的QObject派生類的代碼仍然可以編譯,但這很可能會發生,但根據您使用的特定版本的Qt/moc,導致在運行時在垃圾指針上調用timerSlot()方法。)

+0

是的,它是從QObject繼承的 – PnotNP

0

由於定時器超出了對象範圍,我只需要觸發一次就可以發生極其罕見的崩潰。我使用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); 

因此,由於上下文對象釋放計時器,不會發生崩潰。

-1

達到確定性,停止定時器自己:

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

那不是我問 – PnotNP

+0

@NullPointer。如果你這樣實現它,你的問題是毫無意義的! – Roland

+0

@NullPointer:你的問題報告不僅包含問題,還包含崩潰報告,這是編程藝術中最不合格的結果。因此,我假設你的主要目標是避免程序崩潰,併爲你提供程序設計,避免可疑的崩潰原因。 把我和亞歷山大的建議作比較,並做出最合適的綜合。 – Roland

相關問題