首页 > 其他分享 >Qt QTimer::singleShot问题及用法

Qt QTimer::singleShot问题及用法

时间:2023-05-11 11:03:02浏览次数:28  
标签:const Qt msec singleShot receiver QTimer

问题描述

问题描述:QTimer::singleShot定时器事件超时,如果此时类内对象已经被回收,定时器事件调用已经释放的类内资源时会引起崩溃

 1 void func()
 2 {
 3     QTimer::singleShot(50,[=](){
 4         this->continueNodeTask();
 5     });
 6 }
 7 
 8 /*
 9 如果singleShot事件已经注册,当前类对象已经回收,定时时间到期后相应类对象已经回收,调用会引起指针错误
10 核心原因是 事件和类的生命周期不一致
11 应当保持类内事件与类内对象声明周期保持一致
12 */
13 
14 //QTimer::singleShot等价写法
15 QTimer* t = new QTimer(this);
16 connect(t,QTimer::timeout,[=](){
17     t->stop();
18     t->deleteLater();
19 
20     this->continueNodeTask();
21 });
22 t->start(50);

以上写法能实现singleShot但是太过臃肿,经过仔细发现QTimer有相应的处理方式

singleShot使用需要注意的点
singleShot有很多重载函数,各有自己的使用场景,使用不当,容易导致奔溃或者达不到预期。

1、时间精度:

查看源码可知,调用的时候若没有传入Qt::TimerType参数,传入的超时时间小于等于2000ms时,QT自动选择使用精度更高的时钟类型:Qt::PreciseTimer,否则使用精度次高的Qt::CoarseTimer

1 void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
2 {
3     // coarse timers are worst in their first firing
4     // so we prefer a high precision timer for something that happens only once
5     // unless the timeout is too big, in which case we go for coarse anyway
6     singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, receiver, member);
7 }

2、不恰当使用lambda表达式导致奔溃

如下为singleShot使用lambda的两种常用方式,区别在于第二个参数,为了访问类成员,lambda都捕获this指针。

方式1:若对话框对象在超时前已经销毁,则超时时会调用lambda,而lambda捕获了this指针,这时导致奔溃。

方式2:第二个参数传入this指针,若对话框对象在超时前销毁,超时时间到了也不会调用lambda,所以不会奔溃。

 1 void TestDlg::on_pushButton_clicked()
 2 {    
 3     //方式1
 4     QTimer::singleShot(2000, [this]()
 5     {
 6         //访问类成员
 7     });
 8     
 9     //方式2
10     QTimer::singleShot(2000, this, [this]()
11     {
12         //访问类成员
13     });
14 }

见Qt助手说明:

[static] void QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method)
This is an overloaded function.
This static function calls a member function of a QObject after a given time interval.
It is very convenient to use this function because you do not need to bother with a timerEvent or create a local QTimer object.
The receiver is the receiving object and the method is the member function. The time interval is msec milliseconds.
If receiver is destroyed before the interval occurs, the method will not be called. The function will be run in the thread of receiver. The receiver's thread must have a running Qt event loop.
Note: This function is reentrant.
This function was introduced in Qt 5.4.
See also start().

If receiver is destroyed before the interval occurs, the method will not be called

如果接收者在定时时间到达之前被销毁,相应的方法不会调用

1、第一种超时到后仍然会调用lambda

 

 1 QTimer::singleShot(2000,[this](){
 2     this->doSomething();
 3 });
 4 //若对话框对象在超时前已经销毁,则超时时会调用lambda,而lambda捕获了this指针,这时导致奔溃
 5 
 6 //函数原型
 7 template <typename Duration, typename Func1>
 8     static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
 9                                           !std::is_same<const char*, Func1>::value, void>::type
10             singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Func1 slot)
11     {
12         //compilation error if the slot has arguments.
13         typedef QtPrivate::FunctionPointer<Func1> SlotType;
14         Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) <= 0,  "The slot must not have any arguments.");
15 
16         singleShotImpl(interval, timerType, context,
17                        new QtPrivate::QFunctorSlotObject<Func1, 0,
18                             typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot)));
19     }

2、第二种超时到之前receiver已经被销毁则不会调用lambda.

 1 QTimer::singleShot(2000,this,[this](){
 2     this->doSomething();
 3 });
 4 
 5 //若对话框对象在超时前已经销毁,则超时时不会调用lambda,
 6 
 7 //函数原型
 8 static void singleShot(int msec, const QObject *receiver, const char *member);
 9 
10 //内部调用过程
11 /*!
12     \reentrant
13     This static function calls a slot after a given time interval.
14     It is very convenient to use this function because you do not need
15     to bother with a \l{QObject::timerEvent()}{timerEvent} or
16     create a local QTimer object.
17     Example:
18     \snippet code/src_corelib_kernel_qtimer.cpp 0
19     This sample program automatically terminates after 10 minutes
20     (600,000 milliseconds).
21     The \a receiver is the receiving object and the \a member is the
22     slot. The time interval is \a msec milliseconds.
23     \sa start()
24 */
25 void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
26 {
27     // coarse timers are worst in their first firing
28     // so we prefer a high precision timer for something that happens only once
29     // unless the timeout is too big, in which case we go for coarse anyway
30     singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, receiver, member);
31 }
32 
33 
34 QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char *member)
35     : QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(true), slotObj(nullptr)
36 {
37     timerId = startTimer(msec, timerType);
38     connect(this, SIGNAL(timeout()), r, member);
39 }
40 
41 class QSingleShotTimer : public QObject
42 {
43     Q_OBJECT
44     int timerId;
45     bool hasValidReceiver;
46     QPointer<const QObject> receiver;
47     QtPrivate::QSlotObjectBase *slotObj;
48 public:
49     ~QSingleShotTimer();
50     QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char * m);
51     QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj);
52 Q_SIGNALS:
53     void timeout();
54 protected:
55     void timerEvent(QTimerEvent *) override;
56 };
57 
58 void QSingleShotTimer::timerEvent(QTimerEvent *)
59 {
60     // need to kill the timer _before_ we emit timeout() in case the
61     // slot connected to timeout calls processEvents()
62     if (timerId > 0)
63         killTimer(timerId);
64     timerId = -1;
65     if (slotObj) {
66         // If the receiver was destroyed, skip this part
67         if (Q_LIKELY(!receiver.isNull() || !hasValidReceiver)) {
68             // We allocate only the return type - we previously checked the function had
69             // no arguments.
70             void *args[1] = { nullptr };
71             slotObj->call(const_cast<QObject*>(receiver.data()), args);
72         }
73     } else {
74         emit timeout();
75     }
76     // we would like to use delete later here, but it feels like a
77     // waste to post a new event to handle this event, so we just unset the flag
78     // and explicitly delete...
79     qDeleteInEventHandler(this);
80 }

 

标签:const,Qt,msec,singleShot,receiver,QTimer
From: https://www.cnblogs.com/ybqjymy/p/17390406.html

相关文章

  • Qt QTimer::singleShot用法
    [static]voidQTimer::singleShot(intmsec,constQObject*receiver,constchar*member)这个静态函数在一个给定时间间隔msec(毫秒)之后调用一个槽。用法1:假设类A有个槽函数function(){}我们要在10s之后执行它就可以: QTimer::singleShot(10*1000,this,&A::func......
  • Qt - 中英文翻译
    步骤如下:1、创建ts文件 2、修改UI,并更新ts文件 3、翻译工具打开进行翻译 4、发布生成qm文件 5、将qm文件加入到qrc文件中 6、软件代码中实现   ......
  • 龙芯3a5000处理器下编译Qt源码
    1、下载Qt源码,archive/qt/5.12/5.12.8/single/qt-everywhere-src-5.12.8.tar.xz2、安装依赖库:sudoapt-getinstallflexsudoapt-getinstallbisonsudoapt-getinstallgperfsudoapt-getinstallbuild-essentialsudoapt-getinstalllibgl1-mesa-devsudoapt-getin......
  • qt导入头文件报错
    刚交接同事的qt项目,环境是: 工程中在源代码引用文件或自己写方法调用到一些外部或系统库,编译会报一大堆错,重复引用等等。这种情况在vc上面是不会出现,搞不懂qt为什么这样,急暂未找到解决方案。尝试了一两天,后来发现不要再原来代码写,单独从工程菜单添加先模块,在新模块里面去写,然后......
  • Qt开发-共享内存使用范例,配合开发者密钥使用后台调试程序或者进入调试模式
    共享内存就之前不是开发了一个Leventure_DeveloperKey用以调试程序嘛,在这里简单聊一下调试模式的方案。这里的调试分为了两种,一种是调试模式,一种是开发者模式。需要这两种模式的原因也很简单:1.在远程调试的时候,我可能需要程序从头开始进入调试,这就要求程序一直卡在开头的某个位......
  • QT中线程睡眠对数据IO的影响——串口bug记录
    这两天用QT做一个上位机,涉及到有一个数据发送完后需要用到延时,我一开始使用了线程休眠的方式进行延时://发送读取指令if(serialport->write(data)==-1){qDebug()<<"发送失败!";}QThread::msleep(1000);serialport->clear();然后我发现data并没有被发......
  • Qt XML读写之 QXmlStreamReader、QXmlStreamWriter
    OverviewQtXML将不再接收额外的功能。对于迭代地读取或编写XML文档(SAX),Qt建议使用QtCore的QXmlStreamReader和QXmlStreamWriter类。这些类既易于使用,又更符合XML标准。但是遗憾的是如果想修改更新XML文档,这个模块没有提供解决方案,还只能使用QDomDocument。QXmlStreamReader类......
  • MQTT-保留消息和遗嘱消息
    保留消息为什么需要保留消息        如果不考虑持久会话的因素,那么MQTT订阅只有在客户端连接之后才能创建,所以服务端不能提前预知某个主题会被哪些服务端订阅或者某个客户端会订阅哪些主题,所以当消息到达服务端之后,服务端只会把消息分发给当前已经存在的订阅者,......
  • QT 获取下载文件大小
    1开发环境linux版本:统信UOS1030(可以认为是特殊的ubuntu)开发语言:C++QT:5.9.92实现代码头文件#include<QtNetwork>Qt.pro中需要加对应一行QT+=network函数代码:intgetFileInfoSize(QStringurl){qDebug()<<"getFileInfoSizeurl:"<<url.toSt......
  • 【PyQt6】Python实现QComboBox显示文本与对应值不同的方法
    问题实现QComboBox显示文本与对应值不同的方法。比如下拉框显示“正确”和“错误”,但程序中想要获取“1”和“0”,但又不想再根据显示内容来判断。解决#设置combobox.addItem("正确",1)combobox.addItem("错误",0)#获取text=combobox.currentText()#正确/错误val......