C++ 创建QGenericArgument

C++ 创建QGenericArgument,c++,qt,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() { d

使用简单的应用程序测试
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);
}

我在
setText
值中得到
0
321
到哪里去了?

让我们看看引擎盖下面发生了什么

似乎整数321被视为(const)ref:

Q_ARG
只是一个宏:

#define Q_ARG(type, data) QArgument<type >(#type, data)
。。。这反过来又基于
qgenericalargument

template <class T>
class QArgument: public QGenericArgument
{
public:
    inline QArgument(const char *aName, const T &aData)
        : QGenericArgument(aName, static_cast<const void *>(&aData))
        {}
};
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;
};
class Q\u CORE\u导出qgenericalargument
{
公众:
内联qgenericalargument(const char*aName=Q_NULLPTR,const void*aData=Q_NULLPTR)
:_data(aData),_name(aName){}
内联void*data()常量{return const_cast(_data);}
内联常量char*name()常量{return\u name;}
私人:
const void*_数据;
常量字符*_名称;
};
整个链只包含指向数据的常量指针,因此安全的做法是,问题可能是对临时变量的悬空引用

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

然而,根据CPP对本标准的参考解释:出现问题的原因似乎是:

每当引用绑定到临时对象或子对象时 因此,临时的生存期被延长以匹配 引用的生存期,包括以下异常情况:

(……)

临时绑定到构造函数初始值设定项中的引用成员 列表仅在构造函数退出之前持续存在,而不是在 对象存在。(注:截至1696年DR,此类初始化的格式不正确)

如果我的解释是正确的(不确定在本例中是否
pointer==reference
),则程序处于愉快的未定义行为状态(运行
invokeMethod
时,Qt需要取消对悬挂指针/ref的引用)


由于它不会崩溃并使用0值(你怎么知道它被调用了?你调试过了吗?),因此构建配置可能隐藏了问题。

让我们看看引擎盖下发生了什么

似乎整数321被视为(const)ref:

Q_ARG
只是一个宏:

#define Q_ARG(type, data) QArgument<type >(#type, data)
。。。这反过来又基于
qgenericalargument

template <class T>
class QArgument: public QGenericArgument
{
public:
    inline QArgument(const char *aName, const T &aData)
        : QGenericArgument(aName, static_cast<const void *>(&aData))
        {}
};
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;
};
class Q\u CORE\u导出qgenericalargument
{
公众:
内联qgenericalargument(const char*aName=Q_NULLPTR,const void*aData=Q_NULLPTR)
:_data(aData),_name(aName){}
内联void*data()常量{return const_cast(_data);}
内联常量char*name()常量{return\u name;}
私人:
const void*_数据;
常量字符*_名称;
};
整个链只包含指向数据的常量指针,因此安全的做法是,问题可能是对临时变量的悬空引用

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

然而,根据CPP对本标准的参考解释:出现问题的原因似乎是:

每当引用绑定到临时对象或子对象时 因此,临时的生存期被延长以匹配 引用的生存期,包括以下异常情况:

(……)

临时绑定到构造函数初始值设定项中的引用成员 列表仅在构造函数退出之前持续存在,而不是在 对象存在。(注:截至1696年DR,此类初始化的格式不正确)

如果我的解释是正确的(不确定在本例中是否
pointer==reference
),则程序处于愉快的未定义行为状态(运行
invokeMethod
时,Qt需要取消对悬挂指针/ref的引用)


因为它不会崩溃并且使用0值(你怎么知道它被调用了?你调试过吗?),所以你的构建配置隐藏了这个问题。

来自
qgenericalargument
的文档:“这个类不应该被直接使用。”

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

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

要理解为什么这是正确的,而您的代码是不正确的,请参见hauron的答案,但一般来说,您应该遵循手册。

来自
qgenericalargument
的文档:“决不能直接使用此类。”

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

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

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

我在调试时从断点了解
0
。但是如何传递函数的参数呢?@vico既然您可以调试,我建议您在
genericArg
上放置一块手表。将为
invokeMethod
调用复制它。Qt可能会多次复制参数(不确定它们如何解析此函数调用)。另外,便宜的方法是尝试将整数定义为局部变量,看看这是否有帮助,因为您不再有danling参考。我在调试时从断点了解
0
。但是如何传递函数的参数呢?@vico既然您可以调试,我建议您在
genericArg
上放置一块手表。将为
invokeMethod
调用复制它。Qt可能会多次复制参数(不确定它们如何解析此函数调用)。另外,便宜的方法是尝试将整数定义为局部变量,看看这是否有帮助,因为您不再有danling ref。请添加Qt版本和窗口声明。问题无法产生请添加Qt版本和窗口声明。这个问题是无法产生的