connect(&communication_thread,&QThread::started,communication,&Communication::RunFunction);
在 Qt 中, connnect里的4个参数都是传的地址,信号和槽函数都是成员变量,属于栈对象
&communication_thread
使用取地址符 &
是因为 communication_thread
是一个 栈对象(stack-allocated object),而非通过 new
创建的堆对象。以下是详细解释:
1. 为什么这里用 &
?
(1) communication_thread
的存储位置
- 栈对象:
在代码中,communication_thread
是直接声明的成员变量(如QThread communication_thread;
),属于 栈对象(或类成员对象)。它的生命周期由作用域或父对象管理,无需手动delete
。 - 取地址:
因为moveToThread()
需要传入一个QThread*
(指针),而communication_thread
是对象本身,所以需要用&
取其地址:communication->moveToThread(&communication_thread); // 传递 QThread*
(2) 对比 new
创建的线程对象
如果 communication_thread
是通过 new
创建的堆对象,则应直接传递指针:
QThread* communication_thread = new QThread(this); // 堆对象
communication->moveToThread(communication_thread); // 无需 &,已是指针
2. 关键区别:栈对象 vs 堆对象
特性 | 栈对象(QThread thread; ) | 堆对象(QThread* thread = new QThread; ) |
---|---|---|
内存管理 | 自动销毁(作用域结束或父对象析构时) | 需手动 delete 或设置父对象自动删除 |
指针传递 | 需用 & 取地址(如 &thread ) | 直接传递指针(如 thread ) |
典型场景 | 生命周期与类/函数一致时使用 | 需动态控制生命周期时使用 |
3. 为什么此处选择栈对象?
- 生命周期绑定:
通常线程对象 (QThread
) 会作为成员变量存在,其生命周期与所属类(如MainWindow
)一致,无需手动管理。 - 安全性:
栈对象在父对象析构时自动销毁,避免内存泄漏。
4. 注意事项
-
线程对象销毁顺序:
确保线程对象 (communication_thread
) 的析构发生在所有依赖它的对象(如communication
)之后,否则可能引发崩溃。- 如果
communication_thread
是成员变量,通常会在类的析构函数中停止线程:~MainWindow() { communication_thread.quit(); communication_thread.wait(); }
- 如果
-
跨线程信号槽:
如果communication
对象通过moveToThread
移入线程,其槽函数将在新线程执行,需确保线程安全(如避免直接操作 UI)。
5. 完整示例
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow() {
communication = new Communication(); // 堆对象
communication->moveToThread(&communication_thread); // 栈对象取地址
connect(&communication_thread, &QThread::started, communication, &Communication::run);
communication_thread.start();
}
~MainWindow() {
communication_thread.quit();
communication_thread.wait();
delete communication; // 需手动删除堆对象
}
private:
QThread communication_thread; // 栈对象
Communication* communication; // 堆对象
};
总结
&communication_thread
:
因为communication_thread
是栈对象,需用&
取地址以传递指针给moveToThread
。- 何时用
&
:
当对象是栈对象或成员对象时,取地址传递指针;堆对象直接传递指针本身。 - 生命周期管理:
确保线程和依赖对象的销毁顺序正确,避免悬空指针。