有简单的应用程序来测试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
值中获得setText
。 321
哪里消失了?
答案 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的回答,但一般来说你应该遵循手册。