Russian Qt Forum
Апрель 20, 2024, 06:26 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Простой пример с прогнозом погоды. Падает приложение.  (Прочитано 6437 раз)
8Observer8
Гость
« : Июль 08, 2014, 13:07 »

Привет!

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

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



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

Заранее спасибо за помощь!
« Последнее редактирование: Июль 08, 2014, 13:10 от 8Observer8 » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #1 : Июль 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 уже удален менеджером и грохнет его повторно.

« Последнее редактирование: Июль 08, 2014, 13:46 от Old » Записан
8Observer8
Гость
« Ответ #2 : Июль 08, 2014, 14:45 »

Ничего себе! Я бы сам ни за что не догадался поменять местами Улыбающийся Огромное спасибо!

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

Сообщений: 4349



Просмотр профиля
« Ответ #3 : Июль 08, 2014, 14:49 »

У меня такое чувство, что здесь "пахнет" deleteLater().
Нет.

Но пока я не понял взаимосвязь объектов "m_manager" и "m_reply"
m_manager хранит указатели на все свои reply и удаляет их при своем удалении.
unique_ptr так же удаляет объект, указатель на который она хранит.
У вас в начале менеджер удалял reply, а затем unique_ptr старался удалить его повторно.
Записан
8Observer8
Гость
« Ответ #4 : Июль 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;
}
 
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #5 : Июль 08, 2014, 21:58 »

Добавлю еще, что все указатели на производные от QObject иногда удобно держать в QPointer, который будет зачищаться после автоматического удаления (если оно вдруг произойдет) и такие сюрпризы с удалением удаленного объекта не будут происходить.
Записан

Гугль в помощь
8Observer8
Гость
« Ответ #6 : Июль 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. Поправьте, если я неправ Улыбающийся
« Последнее редактирование: Июль 09, 2014, 08:37 от 8Observer8 » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #7 : Июль 09, 2014, 09:04 »

Тут я не понял. Максимум у нас появляется возможность проверить удалён ли объект (то есть невисячий ли указатель).
QPointer может отследить, что объект на который он указывает уже удален и не удалять его в этом случае.
В вашем случае, менеджер может спокойно разрушаться первым и удалить все свои reply, после это деструктор QPointer определит, что объект на который он указывает разрушен и повторно не будет его удалять.
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #8 : Июль 09, 2014, 09:31 »

QPointer не удаляет объект, он только самоочищается когда объект кто-то удалил. Соответственно он не является аналогом std::unique_ptr.

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

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

Гугль в помощь
alex312
Хакер
*****
Offline Offline

Сообщений: 606



Просмотр профиля
« Ответ #9 : Июль 09, 2014, 09:35 »

Я узнал, что эквивалентом для std::unique_ptr является QPointer, а для std::shared_ptr - QSharedPointer Улыбающийся
QPointer не является эквивалентом std::unique_ptr, потому что при удалении Qpointer, он не удаляет обьект на который указывает.  
Эквивалентом для std::unique_ptr в Qt выступает QScopedPointer.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Июль 09, 2014, 09:52 »

Ах сколько видов "умности" указателей (и не только Улыбающийся). А почему m_reply член? Если им владеет m_manager, может лучше передавать возвращаемый reply как аргумент везде? Или сделать членом др класса "обработчика" который живет до обновления ответа. В конце-концов что мешает объявить его "просто указателем" и не удалять? Как делается со всеми QWidget * во всех примерах UI - не удаляем сами т.к. есть кому удалять.
Записан
carrygun
Гость
« Ответ #11 : Июль 09, 2014, 11:49 »

А если менеджер не будет удаляться до выхода, но успеет натягать кучу гетов/постов?
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.115 секунд. Запросов: 22.