创建QGenericArgument

时间:2018-05-23 11:09:57

标签: c++ qt

有简单的应用程序来测试QMetaObject::invokeMethod目的:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::setText( int value)
{
    QString s = QString::number(value);
    ui->textEdit->setText(s);
}





void MainWindow::on_pushButton_clicked()
{
    QGenericArgument genericArg =  Q_ARG(int, 321);
    bool inv = QMetaObject::invokeMethod( this,"setText",Qt::QueuedConnection, genericArg);
    qDebug("inv = %d\n", inv);
}

我在0值中获得setText321哪里消失了?

2 个答案:

答案 0 :(得分:3)

让我们来看看幕后发生的事情。

似乎整数321被视为(const)ref https://doc.qt.io/qt-5/qmetaobject.html#Q_ARG

QGenericArgument Q_ARG(Type, Type &value)
QGenericArgument Q_ARG(Type, const Type &value)

Q_ARG只是一个宏:

#define Q_ARG(type, data) QArgument<type >(#type, data)

..返回类QArugment的对象:

template <class T>
class QArgument: public QGenericArgument
{
public:
    inline QArgument(const char *aName, const T &aData)
        : QGenericArgument(aName, static_cast<const void *>(&aData))
        {}
};

...反过来又基于QGenericArgument

class Q_CORE_EXPORT QGenericArgument
{
public:
    inline QGenericArgument(const char *aName = Q_NULLPTR, const void *aData = Q_NULLPTR)
        : _data(aData), _name(aName) {}
    inline void *data() const { return const_cast<void *>(_data); }
    inline const char *name() const { return _name; }

private:
    const void *_data;
    const char *_name;
};

这整个链只包含指向数据的常量指针,所以一个安全的赌注是问题是对临时的悬挂引用。

由于数据321只是一个临时数据,因此当Q_ARG被解析为构造函数时,它首先绑定到const引用,这没关系。

然而,根据标准的cppreference解释:https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary问题似乎是由于:

  

每当引用绑定到临时对象或子对象时   其中,临时的寿命延长以匹配   参考的生命周期,包含以下例外

     

(...)

     

临时绑定到构造函数初始值设定项中的引用成员   list只会持续存在,直到构造函数退出,而不是只有   对象存在。 (注意:从DR 1696开始,这种初始化是不正确的)

如果我的解释是正确的(在这种情况下不确定是否pointer == reference),那么程序处于愉快的未定义行为状态(Qt在运行invokeMethod时需要取消引用悬空指针/ ref )。

因为它没有崩溃并使用0值(你怎么知道它被调用了?你调试了吗?)可能是你的构建配置隐藏了这个问题。

答案 1 :(得分:1)

来自QGenericArgument的文档:“不应该直接使用此类。”

事实上,通过遵循手册来解决问题:

void MainWindow::on_pushButton_clicked()
{
    bool inv = QMetaObject::invokeMethod( this,"setText",
        Qt::QueuedConnection, Q_ARG(int, 321));
    qDebug("inv = %d\n", inv);
}

要理解为什么这是正确的而你的代码没有,请参阅hauron的回答,但一般来说你应该遵循手册。