• 9598阅读
  • 9回复

QT 信号与槽的参数转存 [复制链接]

上一主题 下一主题
离线jasonhit
 

只看楼主 倒序阅读 楼主  发表于: 2009-08-27
信号与槽的连接有Qt::DirectConnection, Qt::QueuedConnection等模式,用Qt::QueuedConnection模式的话,信号与槽之间的参数就有可能需要转存了。
例如:
typedef struct my_type
{
   QString q_str;
    int i;
}MY_TYPE;

signals: signal_method(MY_TYPE str )

slot: slot_method(MY_TYPE str )

QT会把信号发过来的参数拷贝一份,然后等槽要执行的时候,交给槽。

但如果我们定义信号、槽的时候,若果用的是引用参数,情况又会如何? 从测试来看,QT不会拷贝参数。这也符合引用的使用。但问题来了,信号传递过来的引用是局部变量,信号发射完就过了生命周期,这样槽执行拿到的引用还会有效吗? 测试的结果来看,信号传递的引用过了生命周期,但槽还能拿到引用的内容。

C++的引用像unix 文件系统 硬链接还是软连接呢?

#include <QtGui/QApplication>
#include "iostream"
#include "qdebug"

using namespace std;

typedef struct aa
{
    QString q_str;
    int i;
}AA;

AA t3;

AA &t =  t3;

void pass();

int main(int argc, char *argv[])
{

    pass();

    cout << qPrintable(t.q_str) << endl;

    int ci;
    cin >> ci;

}


void pass()
{
    AA *t2 = new AA();
    t2->i = 5;
    t2->q_str = "my test str";

    t = *t2;

    delete t2;
}

结果的输出为何还是"my test str"? 是delete 没有重置 t2指向的内存?
[ 此帖被jasonhit在2009-08-27 13:08重新编辑 ]
离线shiroki

只看该作者 1楼 发表于: 2009-08-27
引用类似于指针, 应该算软连接
AA &t =  t3; 这句话类似于让t指向t3的地址
t = *t2; 这句话则类似于把t2的内容复制给t3.
所以delete t2不会对t有影响

你可以查查t3的内容, 看看是不是这样
--
shiro is White
ki is tree
http://www.cuteqt.com
论坛 http://www.cuteqt.com/bbs
博客 http://www.cuteqt.com/blog
博客镜像: http://sites.cuteqt.com/cuteqt
Linux/Qt/嵌入式讨论群 http://qun.qq.com/air/5699823
离线jasonhit

只看该作者 2楼 发表于: 2009-08-27
引用第1楼shiroki于2009-08-27 13:35发表的  :
引用类似于指针, 应该算软连接
AA &t =  t3; 这句话类似于让t指向t3的地址
t = *t2; 这句话则类似于把t2的内容复制给t3.
所以delete t2不会对t有影响
.......


谢谢shiroki。

恩,应该是这样的。


至于信号与槽的参数,在connect的时候好像是不支持引用的。也就是connect(this, SIGNAL(sender(MY_TYPE &)), this, SLOT(receiver(MY_TYPE &))), 这里用MY_TYPE &是有错的,但用MY_TYPE * 就可以。
离线shiroki

只看该作者 3楼 发表于: 2009-08-27
不会呀, qt本身的信号和槽有很多用到引用的. 比如 Model的index经常用引用传来传去的. 估计你的程序什么地方写错了吧
--
shiro is White
ki is tree
http://www.cuteqt.com
论坛 http://www.cuteqt.com/bbs
博客 http://www.cuteqt.com/blog
博客镜像: http://sites.cuteqt.com/cuteqt
Linux/Qt/嵌入式讨论群 http://qun.qq.com/air/5699823
离线jasonhit

只看该作者 4楼 发表于: 2009-08-28
引用第3楼shiroki于2009-08-27 15:27发表的  :
不会呀, qt本身的信号和槽有很多用到引用的. 比如 Model的index经常用引用传来传去的. 估计你的程序什么地方写错了吧



恩,确实是搞错了,QT的信号与槽的参数如果是引用的话,得加const 才行。

在信号与槽的参数中,用引用与用指针在转存参数的时候是有区别的。用引用的话,在转存参数的时候,QT还是会把参数拷贝出来,这点可以用局部变量测试出来。因为用局部变量,用引用的话,可以把参数从信号传递到槽,而用指针的话,则出错。
离线shiroki

只看该作者 5楼 发表于: 2009-08-28
事实证明,你的理解仍然有问题。 还是检查检查你的程序哪里写错了吧
[ 此帖被shiroki在2009-08-28 11:29重新编辑 ]
附件: example.tar.gz (137 K) 下载次数:16
--
shiro is White
ki is tree
http://www.cuteqt.com
论坛 http://www.cuteqt.com/bbs
博客 http://www.cuteqt.com/blog
博客镜像: http://sites.cuteqt.com/cuteqt
Linux/Qt/嵌入式讨论群 http://qun.qq.com/air/5699823
离线jasonhit

只看该作者 6楼 发表于: 2009-08-28
引用第5楼shiroki于2009-08-28 11:24发表的  :
事实证明,你的理解仍然有问题。 还是检查检查你的程序哪里写错了吧



shiroki,非常感谢你的例子。

是的,没错,当QT的信号与槽的参数不需要转存的时候是可以不用加const的。但参数需要用转存的时候就不行了。

我把connect(this, SIGNAL(sigTryMe(QImage&)), this, SLOT(sloTryMe(QImage&)), Qt::QueuedConnection); 加上了Qt::QueuedConnection,程序运行就不正确了。QT4.5默认是auto的,也就是在同一个线程里面,是用DirectConnection,但不同线程里面是用QueuedConnection的。所以在Qt::QueuedConnection的参数就需要转存了,也就是QT需要把信号发过来的参数先缓存起来,等到调用槽的时候,再把参数取出来,交给槽去运行。在转存的时候,当参数是引用的时候,QT是如何去缓存那些参数的呢?我测试来看,是拷贝的。

当connect的时候用上了Qt::QueuedConnection,则需要在信号、槽的参数加上const,那样程序又运行正确了。


环境:QT 4.5, qt-add-in, vs2005
离线shiroki

只看该作者 7楼 发表于: 2009-08-28
恩, 这个问题主要是变量运行期的问题。  queuedconnection等到slot调用的时候参数的运行期已经过了,引用就无效了。
至于变成const,const变量在单独的常量区定义(不在stack里), 整个程序的生命周期都是有效的, 和普通的auto变量不太一样。 我觉得应该是这一点造成的结果。
不管如何传引用的话应该由程序去保证参数的有效性。
--
shiro is White
ki is tree
http://www.cuteqt.com
论坛 http://www.cuteqt.com/bbs
博客 http://www.cuteqt.com/blog
博客镜像: http://sites.cuteqt.com/cuteqt
Linux/Qt/嵌入式讨论群 http://qun.qq.com/air/5699823
离线jasonhit

只看该作者 8楼 发表于: 2009-08-28
难道说,函数的引用参数,加上const,使得实参的生命周期不一样了? 这点不太好理解了。
离线beajisong

只看该作者 9楼 发表于: 2009-08-29
QT在传参的过程中,有时向上面所述是需要转储参数
但是
const QString& 和QString两类参数在对待上并没有区别
这也是为啥上面有人说非要const的问题
而且转储参数必须为QT已识别的类型,也就是说QMeta系统了解的。
自定义类型需要注册一下
而且,因为是转储还需要提供拷贝构造函数和赋值操作符
最后,常引用和局部变量参数都是转储拷贝对象。
快速回复
限100 字节
 
上一个 下一个