LINUX.ORG.RU

Удалить испускателя сигнала из слота Qt

 ,


0

1

Доброго времени суток. Появилась такая заморочка. Нужно удалить испускателя сигнала из подключенного к нему слота. Теперь подробнее: Есть метод класса наследника QObject:

void MyAPI::updateHistory(QString param){
    QNetworkAccessManager *api = new QNetworkAccessManager(this);
    connect(api, SIGNAL(finished(QNetworkReply*)), this, SLOT(historyFinished(QNetworkReply*)));
    api->get(QNetworkRequest(QUrl("https://server.com/public?command=returnHistory&param="+param)));
}
void MyAPI::historyFinished(QNetworkReply *reply){
    if (reply->error() == QNetworkReply::NoError){
        emit updatedHistory(QJsonDocument::fromJson(reply->readAll()));
    } else {
        qDebug() << reply->errorString();
        emit historyNotUpdated(reply->errorString());
    }
    qobject_cast<QNetworkAccessManager *>(sender())->deleteLater();        //Правильно ли так делать?
    reply->deleteLater();                                                  //Правильно ли так делать?
}
Все. После того, как сработал слот historyFinished, объект испускатель сигнала (QNetworkAccessManager *api) мне больше не нужен. Хотелось бы его удалить. Я поступал так, как написано в слоте, но не знаю правильно ли так делать? Я бы не сомневался, но иногда (не часто, но случается) у меня в дебаге вываливалось вот такое сообщение: Type conversion already registered from type QSharedPointer<QNetworkSession> to type QObject* И еще. Можно ли вместо reply->deleteLater(); вызывать delete reply?

Ну да ладно. Это пол беды. Такая схема у меня работала до тех пор, пока я не решил вынести реализацию в плагины. Тут тоже схема работает, но иногда при закрытии приложения, в дебаг начинают сыпаться сотни сообщений вида: QSocketNotifier: socket notifiers cannot be disabled from another thread. И приложение зависает намертво. Никак не могу понять с чем это может быть связано, но подозреваю что ноги тут растут из одного и того же места. Хотя тут у меня подозрение еще на один мой костыль. А именно - в схеме реализации плагинов, предложенном Qt, нет возможности использовать сигналы и слоты. Но задействовав костыль вида:

    connect(dynamic_cast<QObject *>(api_interface), SIGNAL(updatedHistory(QJsonDocument)), this, SLOT(history(QJsonDocument)));
Где api_interface - это объект класса интерфейса для плагина. Сигналы все таки соединяются и все работает нормально. Собственно способ честно нагуглен в интернетах - и у людей такое тоже работало прекрасно.

Так собственно о чем это я? Не подскажете в чем мой косяк? И почему данные ошибки проявляются не всегда?

qobject_cast<QNetworkAccessManager *>(sender())->deleteLater(); //Правильно ли так делать?

Можно просто sender() -> deleteLater(). Еще можно добавить проверку на nulptr

Хотя тут у меня подозрение еще на один мой костыль

А ты плагины перед завершением приложения удаляешь? У меня как то тоже было проблема при завершении приложения.. оно просто валилось в segfault. Вылечил добавлением в метод closeEvent строки delete myPlugin

energyclab ()
Ответ на: комментарий от Stil

Ну т.е. это правильное решение? А нужно ли делать так:

qobject_cast<QNetworkAccessManager *>(sender())->deleteLater();
Или можно сразу написать: sender()->deleteLater(); И почему тогда иногда вылазит сообщение об ошибке: Type conversion already registered from type QSharedPointer<QNetworkSession> to type QObject*

И да. Это только половина вопроса. Возможно я поступил неправильно и следовало создать еще одну тему для второй половины. Я просто считаю что мой второй вопрос - вытекает из первого.

Impuls ()
Ответ на: комментарий от energyclab

За упрощение спасибо. Да плагины удаляю. Код загрузки плагина

foreach (QString strFileName, dir.entryList(QDir::Files)) {
        QPluginLoader loader(dir.absoluteFilePath(strFileName));
        APIInterface *interface = qobject_cast<APIInterface *>(loader.instance());
        if (interface){
            ui->comboBoxAPI->addItem(interface->getAPIName(), QVariant::fromValue(interface));
        } else {
            QMessageBox::critical(0, "", loader.errorString());
        }
    }
    for(int i=0; i<ui->comboBoxAPI->count(); ++i){
        APIInterface *interface = qvariant_cast<APIInterface *>(ui->comboBoxAPI->itemData(i));
        delete interface;
    }

Impuls ()
Ответ на: комментарий от Impuls

Прежде, чем удалять, надо все ссылки и указатели снести. У тебя comboBoxAPI -> itemData(i) после вызова delete может положить программу...По-этому, надо сначала его очистить. А вообще можно запустить strace и посмотреть где именно валится, ну, или через дебаггер

energyclab ()
Ответ на: комментарий от Impuls

Или можно сразу написать: sender()->deleteLater();

конечно можно, читай документацию на QObject и QNetworkAccessManager.

alex_custov ★★★★★ ()
Ответ на: комментарий от energyclab

Ну так это все вызывается в деструкторе главной формы. По идее не должен он положить программу. А с дебаггером не понятно как. Эти ошибки не всегда выскакивают.

Impuls ()

Не мог удержаться

Сигналоиспускательный канал.

bk_ ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.