2016-06-17 3 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 

В этом случае после того, как объект удален и таймер уволен, выполнит ли он 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++ функции или увеличения:

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' будет недействительным (без использования). –

+0

Просто примечание: в разделе «без последних возможностей C++» используется 'std :: shared_ptr', который был введен в C++ 11. –

2

Вы не обязаны отключать сигналы и слоты объекта перед его удалением.

QObject деструктор будет очищать устаревшие соединения сигнал-слот для вас, до тех пор, как вы:

  1. Наследовать от QObject

  2. Use the Q_OBJECT macro in your class definition

После этих соглашения обеспечивают, чтобы ваш объект излучал сигнал destroyed() при его удалении. Фактически это то, что использует система сигналов и слотов Qt для очистки оборванных ссылок.

Вы можете сами прослушать сигнал destroyed(), если хотите добавить код отладки для отслеживания объектов lifecycles.

(В зависимости от конкретной версии Qt/moc, которую вы используете, вполне возможно, что код с не-QObject с использованием слотов или класс, полученный QObject, который не имеет Q_OBJECT в своем заголовке, все еще будет компилироваться, но вызвать метод timerSlot(), который будет вызван на указателе мусора во время выполнения.)

+0

Да, это наследуется от QObject – PnotNP

0

Я получаю крайне редкое падение из-за таймер из объектов сферы, которые мне нужно стрелять только один раз. Я использую QTimer :: singleShot, который является статическим методом и не относится к экземпляру объекта QTimer, который я бы выпустил с контекстом, в который он подает сигнал.

Это, конечно, решается в QTimer класса и желаемое поведение контролируемого экземпляра класса таймера с нестатической QTimer::singleShot свойством, установленным в действительности.

// 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