Russian Qt Forum

Qt => Общие вопросы => Тема начата: 8Observer8 от Июль 08, 2014, 13:07



Название: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: 8Observer8 от Июль 08, 2014, 13:07
Привет!

Я написал небольшой пример. Программа отправляет запрос на сервер погоды и получает ответ в XML-формате. На данном этапе, программа только выводит принятый контент с помощью qDebug()

Проблема в том, что когда я закрываю окно, то выдаётся сообщение:

(http://i7.pixs.ru/storage/7/0/0/232png_4215418_12890700.png)

Исходники: https://github.com/8Observer8/Qt_WeatherForecast
Сервер погоды: http://www.worldweatheronline.com/free-weather-feed.aspx

Заранее спасибо за помощь!


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: Old от Июль 08, 2014, 13:30
Переставьте местами:
Код
C++ (Qt)
class NetworkManager : public QObject
{
   ....
   std::unique_ptr<QNetworkAccessManager> m_manager;
   std::unique_ptr<QNetworkReply> m_reply;
};
 

И не стоит хранить указатель на reply в unique_ptr.
reply владеет сам менеджер, и пытается его разрушить при своем разрушении, ну и unique_ptr становиться его владельцем и пытается делать также.
Т.е. если первый reply разрушает unique_ptr, то все нормально, reply выписывается из менеджера и он не пытается ее разрушить повторно, а вот если первым reply разрушит менеджер, то упадет, потому что unique_ptr не знает что reply уже удален менеджером и грохнет его повторно.



Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: 8Observer8 от Июль 08, 2014, 14:45
Ничего себе! Я бы сам ни за что не догадался поменять местами :) Огромное спасибо!

Теперь попытаюсь понять. У меня такое чувство, что здесь "пахнет" deleteLater(). Но пока я не понял взаимосвязь объектов "m_manager" и "m_reply"


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: Old от Июль 08, 2014, 14:49
У меня такое чувство, что здесь "пахнет" deleteLater().
Нет.

Но пока я не понял взаимосвязь объектов "m_manager" и "m_reply"
m_manager хранит указатели на все свои reply и удаляет их при своем удалении.
unique_ptr так же удаляет объект, указатель на который она хранит.
У вас в начале менеджер удалял reply, а затем unique_ptr старался удалить его повторно.


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: 8Observer8 от Июль 08, 2014, 16:30
m_manager хранит указатели на все свои reply и удаляет их при своем удалении.

Спасибо! Теперь понял :)

Output:
Цитировать
constructor of A
constructor of B
destructor of B
destructor of A

main.cpp
Код
C++ (Qt)
 
#include <iostream>
 
class A
{
public:
   A( )
   {
       std::cout << "constructor of A" << std::endl;
   }
 
   ~A( )
   {
       std::cout << "destructor of A" << std::endl;
   }
};
 
class B
{
public:
   B( )
   {
       std::cout << "constructor of B" << std::endl;
   }
 
   ~B( )
   {
       std::cout << "destructor of B" << std::endl;
   }
};
 
void func( )
{
   A a;
   B b;
}
 
int main( )
{
   func( );
   return 0;
}
 


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: navrocky от Июль 08, 2014, 21:58
Добавлю еще, что все указатели на производные от QObject иногда удобно держать в QPointer, который будет зачищаться после автоматического удаления (если оно вдруг произойдет) и такие сюрпризы с удалением удаленного объекта не будут происходить.


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: 8Observer8 от Июль 09, 2014, 08:34
navrocky, спасибо! А почему "иногда"? :)

Я узнал, что эквивалентом для std::unique_ptr является QPointer, а для std::shared_ptr - QSharedPointer :)

NetworkManager.h
Код
C++ (Qt)
#ifndef NETWORKMANAGER_H
#define NETWORKMANAGER_H
 
#include <string>
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QUrl>
#include <QString>
#include <QPointer>
#include "EmptyArgument.h"
 
class NetworkManager : public QObject
{
   Q_OBJECT
 
public:
   NetworkManager( )
   {
       m_manager = new QNetworkAccessManager( this );
   }
 
   void fetch( const QString &url )
   throw ( EmptyArgument )
   {
       std::string functionName = "fetch()";
 
       // Check the input argument
       if ( url.isEmpty( ) ) {
           throw EmptyArgument( functionName );
       }
 
       m_reply = m_manager->get( QNetworkRequest( QUrl( url ) ) );
 
       connect( m_reply, SIGNAL( finished( ) ),
                this, SLOT( replyFinished( ) ) );
   }
 
signals:
   void signalWithContent( QString content );
 
private slots:
   void replyFinished( )
   {
       QByteArray data = m_reply->readAll( );
       QString content( data );
       emit signalWithContent( content );
   }
 
private:
   QPointer<QNetworkAccessManager> m_manager;
   QPointer<QNetworkReply> m_reply;
};
 
#endif // NETWORKMANAGER_H
 

Цитировать
и такие сюрпризы с удалением удаленного объекта не будут происходить.
Тут я не понял. Максимум у нас появляется возможность проверить удалён ли объект (то есть невисячий ли указатель). А чтобы удалений не происходило, то надо использовать QSharedPointer. Поправьте, если я неправ :)


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: Old от Июль 09, 2014, 09:04
Тут я не понял. Максимум у нас появляется возможность проверить удалён ли объект (то есть невисячий ли указатель).
QPointer может отследить, что объект на который он указывает уже удален и не удалять его в этом случае.
В вашем случае, менеджер может спокойно разрушаться первым и удалить все свои reply, после это деструктор QPointer определит, что объект на который он указывает разрушен и повторно не будет его удалять.


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: navrocky от Июль 09, 2014, 09:31
QPointer не удаляет объект, он только самоочищается когда объект кто-то удалил. Соответственно он не является аналогом std::unique_ptr.

Цитировать
Тут я не понял
Под сюрпризами я имел ввиду попытку повторного удаление.

Вообще для каждого типа указателей своя область применения, её необходимо знать. Для наследников QObject, которые зацеплены за parent, или которыми владеют всякие менеджеры, QSharedPointer, auto_ptr, unique_ptr, scoped_ptr использовать опасно, QPointer в этом случае облегчает жизнь.


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: alex312 от Июль 09, 2014, 09:35
Я узнал, что эквивалентом для std::unique_ptr является QPointer, а для std::shared_ptr - QSharedPointer :)
QPointer не является эквивалентом std::unique_ptr, потому что при удалении Qpointer, он не удаляет обьект на который указывает.  
Эквивалентом для std::unique_ptr в Qt выступает QScopedPointer (http://qt-project.org/doc/qt-5/qscopedpointer.html).


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: Igors от Июль 09, 2014, 09:52
Ах сколько видов "умности" указателей (и не только :)). А почему m_reply член? Если им владеет m_manager, может лучше передавать возвращаемый reply как аргумент везде? Или сделать членом др класса "обработчика" который живет до обновления ответа. В конце-концов что мешает объявить его "просто указателем" и не удалять? Как делается со всеми QWidget * во всех примерах UI - не удаляем сами т.к. есть кому удалять.


Название: Re: Простой пример с прогнозом погоды. Падает приложение.
Отправлено: carrygun от Июль 09, 2014, 11:49
А если менеджер не будет удаляться до выхода, но успеет натягать кучу гетов/постов?