QVariant存储QObject*后调用函数崩溃,如何校验对象有效性?
问题:QVariant存储QObject指针后,如何校验对象有效性避免崩溃?
问题场景
在QML中通过Q_PROPERTY获取C++侧的QVariant类型对象,调用QVariant::value<QObject*>()时程序崩溃,推测是该QVariant中存储的对象内存已被释放。崩溃栈信息如下:
*** Aborted at 1696848320 (unix time) try "date -d @1696848320" if you are using GNU date *** PC: @ 0x0 (unknown) *** SIGSEGV (@0xf1) received by PID 15139 (TID 0x7f78fe9df200) from PID 241; stack trace: *** @ 0x7f78d1816390 (unknown) @ 0x7f78fa283823 QV4::QObjectWrapper::wrap() @ 0x7f78fa27b8b5 QV4::ExecutionEngine::fromVariant() @ 0x7f78fa32bd06 loadProperty() @ 0x7f78fa32ee47 QV4::QObjectWrapper::getProperty() @ 0x7f78fa4b4a4a QV4::QQmlTypeWrapper::lookupSingletonProperty() @ 0x7f78fa4b64ec QV4::QQmlTypeWrapper::virtualResolveLookupGetter() @ 0x7f78fa28ecd5 QV4::Lookup::resolveGetter() @ 0x7f78fa28f44a QV4::Lookup::getterGeneric() @ 0x7f78fa34cdfc QV4::Moth::VME::interpret() @ 0x7f78fa35587d QV4::Moth::VME::exec() @ 0x7f78fa2c0ba8 QV4::Function::call() @ 0x7f78fa49d34c QQmlJavaScriptExpression::evaluate() @ 0x7f78fa4435c8 QQmlBoundSignalExpression::evaluate() @ 0x7f78fa4440c3 QQmlBoundSignal_callback() @ 0x7f78fa479afc QQmlNotifier::emitNotify() @ 0x7f78fa4207c5 QQmlData::signalEmitted() @ 0x7f78f9820fcd doActivate<>() @ 0x7f78f981a30b QMetaObject::activate() @ 0x7f78fa4149cb QQmlVMEMetaObject::activate() @ 0x7f78fa41954a QQmlVMEMetaObject::metaCall() @ 0x7f78f97f1bf9 QMetaObject::metacall() @ 0x7f78fa47a10e QQmlObjectOrGadget::metacall() @ 0x7f78fa32d175 CallMethod() @ 0x7f78fa32d37b CallPrecise() @ 0x7f78fa32e019 QV4::QObjectMethod::callInternal() @ 0x7f78fa32e055 QV4::QObjectMethod::virtualCall() @ 0x7f78fa34deae QV4::Moth::VME::interpret() @ 0x7f78fa35587d QV4::Moth::VME::exec() @ 0x7f78fa2c0ba8 QV4::Function::call() @ 0x7f78fa49d34c QQmlJavaScriptExpression::evaluate() @ 0x7f78fa4435c8 QQmlBoundSignalExpression::evaluate() 10:45:20: The program has unexpectedly finished.
相关代码示例
main.cpp
{ qmlRegisterSingletonType<HeaderModel>("com.my.example", 1, 0, "HeaderModel", &HeaderModel::qmlInstance); ... }
HeaderModel.hpp
{ Q_PROPERTY(QVariant baseModel READ getBaseModel WRITE setBaseModel NOTIFY baseModelChanged) ... public: QVariant getBaseModel() const; void setBaseModel(const QVariant& baseModel); private: QVariant m_baseModel; }
HeaderModel.cpp
QVariant HeaderModel::getBaseModel() const { // 调试:打印QVariant中的对象属性 if (m_baseModel.canConvert<QObject*>()) { QObject *sp = m_baseModel.value<QObject*>(); qDebug() << " objectName: " << sp->objectName().toStdString(); } return m_baseModel; } void HeaderModel::setBaseModel(const QVariant& baseModel) { m_baseModel = baseModel; emit baseModelChanged(); }
QML文件
Guest.qml
MouseArea{ id: mouseArea onClicked: HeaderModel.baseModel = factorModel // factorModel是已暴露给QML的C++对象 }
Header.qml
... id: header signal tapHandler() onTapHandler: { if(HeaderModel.baseModel !== null){ HeaderModel.baseModel.doSomething() } } MouseArea{ id: mouseArea onClicked: header.tapHandler() }
解决方案
1. 使用QPointer跟踪对象生命周期(最安全)
QVariant存储QObject指针时不会自动跟踪对象销毁状态,改用QPointer<QObject>作为成员变量,它会在对象被销毁后自动置为null:
修改HeaderModel.hpp:
{ // 将QVariant改为QObject*类型的属性 Q_PROPERTY(QObject* baseModel READ getBaseModel WRITE setBaseModel NOTIFY baseModelChanged) ... public: QObject* getBaseModel() const; void setBaseModel(QObject* baseModel); private: QPointer<QObject> m_baseModel; // 用QPointer替代QVariant }修改HeaderModel.cpp:
QObject* HeaderModel::getBaseModel() const { if (m_baseModel) { // 直接判断对象是否存活 qDebug() << "objectName:" << m_baseModel->objectName(); } else { qDebug() << "baseModel已被销毁"; } return m_baseModel; } void HeaderModel::setBaseModel(QObject* baseModel) { if (m_baseModel != baseModel) { m_baseModel = baseModel; emit baseModelChanged(); } }这种方式下,QML侧的
HeaderModel.baseModel !== null判断会自动生效,对象销毁后m_baseModel变为null,QML获取到的就是null。
2. 保留QVariant时的校验方法
如果必须使用QVariant存储,取出指针时用QPointer做安全校验:
QVariant HeaderModel::getBaseModel() const { if (m_baseModel.canConvert<QObject*>()) { QObject* obj = m_baseModel.value<QObject*>(); QPointer<QObject> safePtr(obj); if (safePtr) { // 对象仍存活 qDebug() << "objectName:" << safePtr->objectName(); } else { // 对象已销毁,清空QVariant并通知更新 const_cast<HeaderModel*>(this)->m_baseModel = QVariant(); const_cast<HeaderModel*>(this)->emit baseModelChanged(); } } return m_baseModel; }
3. 管理对象所有权避免意外销毁
确保被存储的QObject对象的生命周期被正确管理:
- 如果是C创建的对象暴露给QML,设置所有权为C持有:
qmlEngine(factorModel)->setObjectOwnership(factorModel, QQmlEngine::CppOwnership); - 在对象析构时主动通知HeaderModel清空引用:
// 假设factorModel所属类的析构函数 FactorModel::~FactorModel() { if (HeaderModel::instance()) { // 获取HeaderModel单例 HeaderModel::instance()->setBaseModel(nullptr); } }
4. QML侧增强校验
在调用对象方法前,增加类型判断:
onTapHandler: { let model = HeaderModel.baseModel; if(model !== null && typeof model === 'object'){ model.doSomething() } }
内容的提问来源于stack exchange,提问作者BaCV
相关产品推荐
相关产品推荐

