QT发射一次信号,槽函数执行了多次的背后思考

我有一个梦想,我写的代码,可以像诗一样优美。我有一个梦想,我做的设计,能恰到好处,既不过度,也无不足。

如题,Qt发射了一次信号,关联的槽函数执行了多次。

Qt 的精髓所在就是信号槽,刚接触qt的时候遇到过一次这个问题,就是明明只发射了一次信号,但是关联的槽函数却执行了多次,当时年少,只是想了个办法解决这个问题,没有真正去了解这个问题,知道今天又出现了这个问题,记录一下前因后果,为后来人填坑。
描述下产生问题的环境:
发射信号的源是一个单例(也叫唯一实例),对应的槽函数在程序的MianWindow中,信号槽的绑定时刻在一个action产生的页面中,导致的情况如下:
打开程序时,第一次点击action打开页面执行的情况正常,在没有关闭程序的时候,再次打开该页面并执行对应的动作时,会执行两次该槽函数,第三次,会执行三次该槽函数…

情况是这么个情况,按照以前第一次遇到这种情况的思维,我的处理方式如下:
设置一个bool变量,使之只有在第一次执行有效,屏蔽掉后面的执行,注意,刚开始工作的时候做这种事情,情有可原,都工作了那么久再出现这种操作,不可原谅!
于是乎本着求真的态度(啊呸!),寻求生命的真谛(啊,再呸!),在一番折腾之后,发现了问题的所在。
信号槽的使用在于信号和槽函数的connect,以往没有出现这种问题,是因为我们绑定的信号的主体的生命周期都是有时间限定的,就是说白了,在该主体完成了它的责任的时候,都会被析构掉,参见一个对话框向程序主页面发送信号,在该对话框关闭(析构后),之前所建立的connect绑定关系也就不在(此处不严谨,为了方便叙述,后文会渗入讲一下),第二次打开该页面的时候,产生的对话框就是一个新的对话框(新New出来的,内存地址都不同),又会重新connect绑定一次,此时执行相应动作,会发现槽函数执行正常。
为什么这次会出现这种情况呢?
看上文的环境叙述,发射的信号源为一个单例,这句话是个重点,单例,意味着什么?意味着在该类实例化之后的唯一实体,它的生命周期在之后的程序运行的整个生命周期都会存在,这就造成了每当我们打开该对话框的时候,都会像第一次打开该对话框时,将该实体的发射信号和对应的槽函数绑定,就会出现一个信号同同一个槽函数进行多次绑定的情况,这也就造成了每当我发射一次该信号的时候,对应的槽函数就会因为被多次绑定,而被触发多次。
解决办法:
1、菜鸟级别(对比我第一次遇到这个问题),通过一个bool变量让只有第一次的触发有效,屏蔽掉后面的触发。
2、每次绑定的环境失效前(如在一个对话框中被绑定,该对话框被关闭则视为失效),执行disconnect()函数,将该绑定解除。
3、在唯一实例(单例)实例化的时候,就将该唯一实例的信号与槽函数绑定,即只执行一次绑定。
深度剖析
qt的信号槽机制延伸点说,是对观察者模式的实现,观察者模式我们具象化来说,就是将每个事件(信号)与事件源和其对应的结果(槽函数)关联起来,加入一条链表中,没此connect都会将一对新的关联加入到链表中,当事件发生时(信号发射时),该链表都会从头遍历一遍,将其对应的结果(槽函数)执行一遍,也就是说,在同一个事件源在将其信号被多次关联绑定connect的时候,一次发射信号,就会一次触发多次槽函数。这次的唯一实例就是一个很好的例子。
这也就是上文多说的不严谨的地方,如果在没有执行disconnect 的时候,即便是该信号源(即发射信号的实体被析构不存在的时候,在观察者的链表中,依然会存在这么一个connect的连接,不同的是,该连接的发射者(即信号源已经不存在了)。
结语
这个故事告诉我们,不管是发射源会不会失效,处于资源最优的情况,我们都应该在发射源失效前,将该绑定解除。

  • 21
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值