Создание QGenericArgument - PullRequest
       2

Создание QGenericArgument

0 голосов
/ 23 мая 2018

Есть простое приложение для тестирования 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? 1008 *

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Из документации QGenericArgument: «Этот класс никогда не должен использоваться напрямую.».

И действительно, проблема решается с помощью следующего руководства:

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

Чтобы понять, почему это правильно, а ваш код - нет, см. Ответ hauron, но в целом вы должны следоватьруководство.

0 голосов
/ 23 мая 2018

Давайте посмотрим, что происходит под капотом.

Кажется, что целое число 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 разрешается в конструкторе, и это нормально..

Однако, согласно интерпретации стандарта cppreference: https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary проблема возникает из-за:

Всякий раз, когда ссылка связана с временной илидля подобъекта время жизни временного объекта увеличивается, чтобы соответствовать времени жизни ссылки, со следующими исключениями :

(...)

временной привязкойссылка на член в списке инициализатора конструктора сохраняется только доКонструктор выходит, не так долго, как объект существует.(примечание: такая инициализация некорректна по состоянию на DR 1696)

Если моя интерпретация верна (не уверен, если pointer == reference в этом случае), то программа находится в состоянии счастливого неопределенного поведения(Qt потребуется разыменовать висячий указатель / ref при запуске invokeMethod).

Поскольку он не аварийно завершает работу и использует значение 0 (откуда вы знаете, что оно вообще вызывается? Вы его отладили?), Возможно, ваша конфигурация сборки скрывает проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...