Qt中以已删除对象为收发参数调用disconnect是否安全?
问题解答
核心结论
你的代码存在未定义行为,不是简单的调用失败返回false。
原因说明
- Qt的
disconnect函数只会安全处理nullptr参数,并不会校验传入的指针是否指向已经释放的内存:- 当子窗口被关闭销毁时,
mPreviouslyActiveWidget成为野指针,指向已经被系统回收的内存 - 此时
disconnect内部会尝试访问该指针对应QObject的内部连接表等私有数据,访问野内存属于标准C++未定义行为,可能出现程序崩溃、随机异常等问题
- 当子窗口被关闭销毁时,
- 额外说明:QObject对象销毁时会自动断开所有关联的信号槽连接,你原本的手动断开逻辑如果指针有效的话属于冗余操作,问题的核心是野指针的访问风险。
修复方案
最简单可靠的方案是将mPreviouslyActiveWidget的类型从原生指针MyWidget*替换为Qt提供的智能指针QPointer<MyWidget>:
QPointer是专门用于持有QObject对象的弱智能指针,当指向的QObject对象被销毁时,QPointer会自动被置为nullptr- 此时向
disconnect传入nullptr参数,函数会直接安全返回false,不会触发任何内存访问
修复后的参考代码:
// 头文件成员变量声明替换为 QPointer<MyWidget> mPreviouslyActiveWidget; // 槽函数实现修改为 void MainWindow::SubWindowActivated(QMdiSubWindow* subWindow) { MyWidget* activeWidget = subWindow ? qobject_cast<MyWidget*>(subWindow->widget()) : nullptr; if (activeWidget == mPreviouslyActiveWidget) { return; } // 此时mPreviouslyActiveWidget如果已经销毁则为nullptr,disconnect安全无风险 disconnect(this, nullptr, mPreviouslyActiveWidget, nullptr); disconnect(mPreviouslyActiveWidget, nullptr, this, nullptr); // 新增与当前activeWidget的连接逻辑 if (activeWidget) { // 你的连接实现 } mPreviouslyActiveWidget = activeWidget; }
如果不想用QPointer,也可以在持有原生指针的同时,绑定mPreviouslyActiveWidget的destroyed信号,收到信号时将指针置空,但实现成本远高于直接使用QPointer。
内容的提问来源于stack exchange,提问作者Unimportant
相关产品推荐
相关产品推荐

