c++ - Q_INVOKABLE const getter 返回 undefined,non-const getter 返回正确值 - 为什么?

标签 c++ qt qml

我有简单的 c++ 类方法:

Q_INVOKABLE const QString& getRiderTypeName(const int& riderTypeIndex) const;

及其实现:
const QString& CumulativeSalesZoneModel::getRiderTypeName(const int& raiderTypeIndex) const   
{
    static QString result=QString();

    if(this->cumulativeSalesZoneData!=Q_NULLPTR)
    {
        result=this->cumulativeSalesZoneData->keys().at(raiderTypeIndex);
    }   // if

    return result;
}   // getRiderTypeName

以及何时从 QML 调用,它返回未定义的值。但是,如果我减少 const运算符,删除 reference并删除 static result 的声明作为返回值的一部分:
Q_INVOKABLE QString getRiderTypeName(const int& riderTypeIndex) const;

及其实现:
QString CumulativeSalesZoneModel::getRiderTypeName(const int& raiderTypeIndex) const
{
    QString result=QString();

    if(this->cumulativeSalesZoneData!=Q_NULLPTR)
    {
        result=this->cumulativeSalesZoneData->keys().at(raiderTypeIndex);
    }   // if

    return result;
}   // getRiderTypeName

我得到正确的值。为什么会这样?我在几个 Qt 上试过这个Windows 上的版本, Linux和几个嵌入式板(Raspeberry PiToradex Colibri iMX6 和其他几个)。在@Azeem 请求下,我添加了相关的QML代码:
Component.onCompleted:
{
    riderTypeName=cumulativeSalesZoneModel.getRiderTypeName(riderTypesIndex);
    console.log(riderTypeName);
}   // Component.onCompleted

控制台输出:
qml: undefined

如果调用了第一个版本的方法,并且如果调用了第二个版本的方法,它会输出正确的值。

最佳答案

Revision # 1 (作为常量引用返回的非静态/本地数据):

const QString& CumulativeSalesZoneModel::getRiderTypeName( /*...*/ )
{
    QString result = QString();    // non-static/local object
    // ...
    return result;
}

答案#1:

在 C++ 端,您试图返回局部变量的地址(引用),即 result .当代码块完成执行时,它将超出范围。所以,你最终得到一个悬空的引用。使用悬空引用将导致 Undefined Behavior .

检查你的编译日志。你一定会收到这样的警告:

warning: reference to stack memory associated with local variable 'result' returned



这是一个重现此警告的示例程序:https://godbolt.org/z/pZBq7H

注意 :一旦代码位于 Qt MOC/QML 端,以下关于返回引用的部分也适用于上面的答案 #1。

Revision # 2 (静态数据作为常量引用返回):
const QString& CumulativeSalesZoneModel::getRiderTypeName( /*...*/ )
{
    static QString result = QString();    // static
    // ...
    return result;
}

根据 Qt Meta Object Compiler页面,它指出(强调我的):

Signals and slots can have return types, but signals or slots returning references will be treated as returning void.



而且,为了验证这一点,我创建了这个小的 test project与多个公众 Q_INVOKABLE方法。 QML 非常简单。返回的字符串显示为 title的 window 。

您需要观察 MOC 生成的文件。

生成的moc_test.cpp包含这部分:
static const uint qt_meta_data_Test[] = {

 // ... code removed for conciseness ...

 // methods: name, argc, parameters, tag, flags
       1,    0,   39,    2, 0x02 /* Public */,
       3,    0,   40,    2, 0x02 /* Public */,
       4,    0,   41,    2, 0x02 /* Public */,
       5,    0,   42,    2, 0x02 /* Public */,
       6,    0,   43,    2, 0x02 /* Public */,

 // methods: parameters
    QMetaType::QString,
    QMetaType::QString,
    QMetaType::QString,
    QMetaType::Void,
    QMetaType::Void,

       0        // eod
};

正如您在上面的代码片段中观察到的(遵循“方法”注释),有 5 种方法。在最后一部分中,只有前 3 个具有返回类型,即 QString但最后 2 个返回 void .

并且,观察以下生成的方法:
void Test::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        auto *_t = static_cast<Test *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: { QString _r = _t->get1_RetByValue_NonConstLocalString();
            if (_a[0]) *reinterpret_cast< QString*>(_a[0]) = std::move(_r); }  break;
        case 1: { QString _r = _t->get2_RetByConstValue_ConstLocalString();
            if (_a[0]) *reinterpret_cast< QString*>(_a[0]) = std::move(_r); }  break;
        case 2: { QString _r = _t->get3_RetByConstValue_StaticString();
            if (_a[0]) *reinterpret_cast< QString*>(_a[0]) = std::move(_r); }  break;
        case 3: _t->get4_RetByConstRef_LocalString(); break;
        case 4: _t->get5_RetByStaticConstRef_StaticString(); break;
        default: ;
        }
    }
}
switch 中的前 3 个案例正确设置参数数组,即 _a但最后2个案例没有。

这里要注意的有趣的事情是前 3 个有效案例中的代码,除了函数调用之外它是相同的,例如:
QString _r = _t->get<...>();    // first 3 variations of get method
if (_a[0]) *reinterpret_cast< QString*>(_a[0]) = std::move(_r);

返回QString分配给 _r然后它被移动分配给 _a[0]来自 _r .

你可以得到project并运行调试 session 以自己观察此行为。我希望这有帮助。

关于c++ - Q_INVOKABLE const getter 返回 undefined,non-const getter 返回正确值 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61038922/

相关文章:

c++ - 如何以UI形式打开QML?

c++ - 确定存储在 std::vector 中的对象是否可以轻松复制

c++ - 如何使用 c++ 客户端/服务器在 openssl 中与 gsoap 一起使用 ssl 证书

c++ - typedef 的有效使用?

c++ - boost - thread.join() 停止 ui

qt - 如何使用snapcraft打包Qt5应用程序

c++ - 将 ICO 文件添加到 Win32 程序

c++ - QtScript 输出重定向

c++ - 了解 Qt View 模型架构 : when to create and how to cleanup indexes in QAbstractItemModel implementation?

c++ - 包含 QML 中的对象的 QAbstractListModel 有哪些缺点?