关于`QObject: Cannot create children for a parent that is in a different thread`

作为一个qt初学者,免不了要踏入QObject: Cannot create children for a parent that is in a different thread这个坑,不论是官方文档、stackoverflow还是csdn,看了半天也摸不着头脑,只好老老实实研究错误代码,最终解决了问题,这里记录一下。
代码从这里开始,一些不同重要的内容就略去了。

Class Worker:public QObject
{
	QTcpSocket tcpSocket;
public:
	Worker();
};

Class Controller:public QObject
{
public:
	Controller();
};

Controller::Controller()
{
	Worker worker=new Worker;
	QThread threads=new Qthreads;
	worker->moveToThread(threads);
	threads->start();
}

这个时候编译,其实也能通过,并且能够执行,但就是在执行的时候qt发出了

QObject: Cannot create children for a parent that is in a different thread
(Parent is QTcpSocket(0xdc3e80), parent's thread is QThread(0xcebf20), current thread is QThread(0xdc4160)

先不管这里什么意思,问题怎么解决呢?就是这样

Class Worker:public QObject
{
	QTcpSocket *tcpSocket;
public:
	Worker()
	{
		tcpSocket=new QTcpSocket(this);
	}
};

这里的关键是在new tcpSocket对象时传入的this参数,这个参数表示tcpSocket这个对象的父对象是这个Worker的一个实例。
我们回头看,为什么这样就可以了。
首先要明确一点,这个错误提示是qt本身对线程处理机制带来的,不是C++本身的问题,也与通常的线程机制无关。
我们可以看到在Controller的构造函数中创建了一个Worker对象worker,以及一个QThread对象threads,然后把这两个对象连接起来。那么问题就是,在Qt看来,调用Controller构造函数的线程,与threads代表的线程是两个线程,而在构造worker时所顺便创建的QTcpSocket对象tcpSocket与worker本身最初同属于Controller所在的线程,worker执行moveToThread之后,worker就转移到了threads所代表的线程中,但是,要注意,tcpSocket仍然属于Controller所在的线程,于是在调用threads->start()的时候就会出现错误提示。
而在构造tcpSocket时如果明确指明其父对象,那么在将worker与threads挂钩时,就会自动的也把tcpSocket与threads挂接起来,于是问题解决。当然,这一点是我猜的,但不管怎么说,执行结果可以证明一切。
显然,如果不使用moveToThread而是重载run来实现线程,其实也是免不了会掉进这个坑,道理上面说了,处理的思路也是一样的。

你可能感兴趣的:(C++,Qt,c++,多线程)