You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:44:53