Russian Qt Forum

Qt => Работа с сетью => Тема начата: voronElf от Декабрь 15, 2009, 08:38



Название: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: voronElf от Декабрь 15, 2009, 08:38
Всем привет.

При использовании QNetworkAccessManager при финише запроса мы получаем объект ответа QNetworkReply. Создает этот объект QNetworkAccessManager и выдает его адрес, а вот насчет удаления этого объекта документация говорит, что удалять нужно ручками самому в коде. Хочу обсудить вопрос: в каком месте кода его удалять (не в конкретной програме, а в принципе) ?

Пробовал удалять в слоте, обрабатывающем сигнал finished(...) от QNetworkAccessManager. Нормально отрабатывает, проблема только в одной ситуации: используем прокси (QNetworkProxy) и если уходил запрос с неправильным логином(паролем) пользователя прокси (код статуса 407, ошибка 105 QNetworkReply) то прога вылетает  по обращении  недоступной памяти.

Если не удалять совсем, почистит ли Qt память с этого объекта по завершению приложения ?

экспериментировал на Qt 4.5.2

PS: Я понимаю, что можно запонинать адреса объектов QNetworkReply и грохать потом в месте кода, где уже гарантированно соединения завершены. Но это уже от конкретного кода зависит, а хотелось бы какой-нибудь унифицированный вариант придумать.


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: Dendy от Декабрь 16, 2009, 23:08
В документации написано, что у QNetworkReply родителем ставится автоматически экземпляр QNetworkAccessManager, значит, что при удалении последнего удалятся и все запросы. Ещё посмотрите в сторону QObject::deleteLater(). Вообще удалять обьекты прямо в слотах опасно, так как обьект, испустивший сигнал, может на следующей строчке обратиться к этому удалённому экземпляру. Нужно смотреть каждый случай в отдельности.


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: voronElf от Декабрь 17, 2009, 11:27
Ну вот видимо при ситуации  с прокси испустивший сигнал объект и обращается к уже удаленному. Покопаю в сторону QObject::deleteLater().


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: Dendy от Декабрь 17, 2009, 11:36
Рекомендую делать: reply->abort(); reply->deleteLater(). Первое по идее заблокирует дальнейшее использование, чтобы на следующей строчке испускающий сигнал код мог проверить его состояние. Второе - прибьёт reply на следующей итерации главного цикла. Вообще в коде Qt встречается подобное:

Код
C++ (Qt)
QPointer self( this );
emit something();
if ( !self )
   return;

Но каждый случай должен быть документирован отдельно, что можно, а что нельзя удалять в слотах.


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: voronElf от Декабрь 18, 2009, 10:48
Потестил (на ситуации с проксей) , достаточно одного reply->deleteLater(), вылетаний памяти уже нет (все таки очищается очередь событий к удаляемому объекту). Но надежнее конечно сначала делать явный reply->abort(). Я ж не абсолютно все ситуации протестил )))

Удалять в слотах конечно способ опасный (документация еще пишет о проблемах QObject::deleteLater() с новыми циклами событий). Но думаю для схемы работы QNetworkReply способ вполне применим. Буду использовать abort() и deleteLater().

P.S. Спасибо за комментарии


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: jjoss от Декабрь 20, 2009, 19:13
Столкнулся с подобной проблемой.
Делаю так.

Код:
class ODSSCon : public QObject
{
Q_OBJECT
.............
private:
  QNetworkAccessManager manager;
  QNetworkRequest request;
  QNetworkReply *currentReply;
..............
public slots:
  void readyReadReply();
  void finishedReadReply();
  void replyError(QNetworkReply::NetworkError error);
..............
};

Затем:
Код:
....
currentReply = manager.get(request);
  connect(currentReply, SIGNAL(readyRead()), SLOT(readyReadReply()));
  connect(currentReply, SIGNAL(finished()), SLOT(finishedReadReply()));
  connect(currentReply, SIGNAL(error(QNetworkReply::NetworkError)),
          SLOT(replyError(QNetworkReply::NetworkError)));
....

И в слоте finishedReadReply() делаю currentReply->deleteLater(); Так же реализован пример QT $QT_DIR\examples\network\downloadmanager\.

Подряд делаю 2 запроса. В итоге, получаю данные только второго. Куда смотреть?


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: Dendy от Декабрь 21, 2009, 03:10
Каждый запрос должен ложиться в отдельную переменную.


Название: Re: Использование QNetworkAccessManager. Где удалять QNetworkReply ?
Отправлено: kataklysm от Ноябрь 10, 2010, 15:05
Каждый запрос должен ложиться в отдельную переменную.
Столкнулся с такой же проблемой. Не подскажите как можно реализовать такое, при этом их n-количество. Спасибо.