Russian Qt Forum

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



Название: [Решено] Использование std::shared_ptr и std::unique_ptr c Qt объектами
Отправлено: 8Observer8 от Июнь 18, 2014, 14:28
Привет!

Захотел начать применять std::shared_ptr для Qt объектов, но сразу столнулся с проблемой. Компилятором выдаётся сообщение:

Цитировать
C:\Qt\Qt5.3.0\Tools\mingw482_32\i686-w64-mingw32\include\c++\ext\new_allocator.h:120: error: cannot allocate an object of abstract type 'QNetworkReply'
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^

Код
C++ (Qt)
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
 
#include <memory>
 
#include <QObject>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetWorkAccessManager>
 
class Downloader : public QObject
{
   Q_OBJECT
 
   Downloader( )
   {
//        connect( m_reply, SIGNAL( finished( ) ),
//                 this, SLOT(replyFinished( ) ) );
   }
 
   void fetch( const QString &url )
   {
       std::shared_ptr<QNetworkAccessManager>
               manager( new QNetworkAccessManager( this ) );
 
       m_reply = std::make_shared<QNetworkReply>( manager->
                                                  get( QNetworkRequest( QUrl( url ) ) ) );
       //m_reply = manager->get( QNetworkRequest( QUrl( url ) ) );
   }
 
signals:
   void signalWithContent( QString * );
 
private slots:
   void replyFinished( )
   {
       QByteArray data = m_reply->readAll( );
       QString content( data );
       emit signalWithContent( &content );
   }
 
private:
   std::shared_ptr<QNetworkReply> m_reply;
   //QNetworkReply *m_reply;
};
 
#endif // DOWNLOADER_H
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 18, 2014, 14:42
Если я не ошибаюсь, то QNetworkReply является абстрактным классом, у него чистая виртуальная функция abort. Нельзя создавать объекты класса QNetworkReply.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 14:56
28Observer8
Что по вашему делает эта строка?

Код
C++ (Qt)
m_reply = std::make_shared<QNetworkReply>( manager->get( QNetworkRequest( QUrl( url ) ) ) );


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 15:17
Если я не ошибаюсь, то QNetworkReply является абстрактным классом, у него чистая виртуальная функция abort. Нельзя создавать объекты класса QNetworkReply.
Хм.. и правда. А почему мы тогда можем создавать объект этого класса через указатель? Как в этом коде:
Код
C++ (Qt)
         QNetworkReply *m_reply;
         QNetworkAccessManager *manager = new QNetworkAccessManager( this );
         m_reply = manager->get( QNetworkRequest( QUrl( url ) ) );
 

А вот так нельзя:
Код
C++ (Qt)
         QNetworkReply *m_reply = new QNetworkReply( this );
[code]
 
[quote author=Old link=topic=27203.msg196820#msg196820 date=1403092573]
28Observer8
Что по вашему делает эта строка?
 
[code=cpp]m_reply = std::make_shared<QNetworkReply>( manager->get( QNetworkRequest( QUrl( url ) ) ) );
[/quote]

Результатом этой команды: manager->get( QNetworkRequest( QUrl( url ) ) ) будет указатель на объект QNetworkReply. Потом этот указатель преобразуется в std::shared_ptr<QNetworkReply>. А уже этим преобразованным указателем инициализируется переменная m_reply. Всё таки нельзя создать std::shared_ptr<QNetworkReply>? Потому что QNetworkReply - это абстрактный класс?[/code][/code]


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 15:22
Результатом этой команды: manager->get( QNetworkRequest( QUrl( url ) ) ) будет указатель на объект QNetworkReply. Потом этот указатель преобразуется в std::shared_ptr<QNetworkReply>. А уже этим преобразованным указателем инициализируется переменная m_reply. Всё таки нельзя создать std::shared_ptr<QNetworkReply>? Потому что QNetworkReply - это чисто виртуальный класс?
Нет.
Эта строка пытается создать (make) объект класса QNetworkReply, передав в качестве параметра конструктору указатель возвращаемый этим: manager->get( QNetworkRequest( QUrl( url ) ) );

Поэтому, у вас ничего не получается. А создать shared_ptr на объект QNetworkReply можно.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 15:32
А почему так можно:

Код
C++ (Qt)
         QNetworkReply *m_reply;
         QNetworkAccessManager *manager = new QNetworkAccessManager( this );
         m_reply = manager->get( QNetworkRequest( QUrl( url ) ) );
 

А так нельзя:
Код
C++ (Qt)
         QNetworkReply *m_reply = new QNetworkReply( this );
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 15:37
А так нельзя:
Потому, что QNetworkReply чисто виртуальный класс.
А в методе get создается объект класса одного из его наследников, поэтому их создавать можно.
Это, как бы, основы основ ООП в C++.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: kambala от Июнь 18, 2014, 15:41
потому что внутри создаются и возвращаются объекты приватных классов-наследников QNetworkReply. можно было просто заглянуть в исходники :)


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 18, 2014, 15:45
manager->get( QNetworkRequest( QUrl( url ) ) ); возвращает указатель на потомка QNetworkReply, но не сам QNetworkReply. Самого объекта QNetworkReply никогда не было и не будет. Это абстракция.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 15:56
В исходниках я нашёл:
Код
C++ (Qt)
/*!
   Posts a request to obtain the contents of the target \a request
   and returns a new QNetworkReply object opened for reading which emits the
   \l{QIODevice::readyRead()}{readyRead()} signal whenever new data
   arrives.
 
   The contents as well as associated headers will be downloaded.
 
   \sa post(), put(), deleteResource(), sendCustomRequest()
*/

QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
{
   return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
}
 

Но мне это не о чём не говорит... Хорошо, допустим, что get() возвращает указатель на объект класса потомка от QNetworkReply. Как узнать, какого потомка мне написать вместо вопросиков:
Код
C++ (Qt)
         m_reply = std::make_shared<???>( manager->
                                                    get( QNetworkRequest( QUrl( url ) ) ) );
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 16:00
Как узнать, какого потомка мне написать вместо вопросиков:
Здесь не нужен make_shared. Объект ответа уже сконструирован внутри get.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 18, 2014, 16:03
а зачем вообще здесь make_shared? заюзай reset
Код:
        
m_reply.reset(manager->get( QNetworkRequest( QUrl( url ) ) ) );


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 16:06
Как узнать, какого потомка мне написать вместо вопросиков:
Здесь не нужен make_shared. Объект ответа уже сконструирован внутри get.

Проблема в том, что я не могу написать так:
Код
C++ (Qt)
         std::shared_ptr<QNetworkReply> m_reply (manager->get( QNetworkRequest( QUrl( url ) ) ) );
 

У меня переменная m_reply объявляется в секции private. А там нельзя инициализировать объекты.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 18, 2014, 16:09
Что значит нельзя инициализировать в секции приват? Смотри мой предыдущий ответ.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 16:12
У меня переменная m_reply объявляется в секции private. А там нельзя инициализировать объекты.
Вначале стоит изучить язык C++. У вас каша в голове. Не обижайтесь. ;)


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 16:34
Что значит нельзя инициализировать в секции приват?
А ведь и вправду можно:
Код
C++ (Qt)
std::shared_ptr<int> foo = std::make_shared<int> (10);
 
Но в моём случае это не подходит. У меня сначала создаётся переменная: std::shared_ptr<QNetworkAccessManager> manager. А потом m_reply.

Смотри мой предыдущий ответ.
Я как раз под него код переписывал и пробовал. Вот так и буду делать. Объявлять переменную:
Код
C++ (Qt)
private:
   std::shared_ptr<QNetworkReply> m_reply;
 

А потом инициализировать:
Код
C++ (Qt)
   std::shared_ptr<QNetworkAccessManager> manager =
           std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
 
   m_reply.reset(manager->get( QNetworkRequest( QUrl( url ) ) ) );
 

Спасибо всем огромное!

Я ещё нашёл, что так нельзя писать:
Код
C++ (Qt)
std::shared_ptr<QNetworkAccessManager>
               manager( new QNetworkAccessManager( this ) );
 

Так как утечки памяти возможны в случае исключений. И вроде два раза место выделяется. Я тонкости ещё не знаю... Вот так правильно:
Код
C++ (Qt)
       std::shared_ptr<QNetworkAccessManager> manager =
               std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
 

Вот так исправил:
Код
C++ (Qt)
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
 
#include <memory>
 
#include <QObject>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetWorkAccessManager>
 
class Downloader : public QObject
{
   Q_OBJECT
 
   Downloader( )
   {
//        connect( m_reply, SIGNAL( finished( ) ),
//                 this, SLOT(replyFinished( ) ) );
   }
 
   void fetch( const QString &url )
   {
       std::shared_ptr<QNetworkAccessManager> manager =
               std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
 
       m_reply.reset(manager->get( QNetworkRequest( QUrl( url ) ) ) );
   }
 
signals:
   void signalWithContent( QString * );
 
private slots:
   void replyFinished( )
   {
       QByteArray data = m_reply->readAll( );
       QString content( data );
       emit signalWithContent( &content );
   }
 
private:
   std::shared_ptr<QNetworkReply> m_reply;
};
 
#endif // DOWNLOADER_H
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 16:43
А вас не смущает, что manager будет разрушаться при выходе из fetch с удалением всех созданных QNetworkReply?


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 16:57
Я думал, что нам объект "manager" нужен только чтобы "m_reply" инициализировать. Разве нет? На всякий случай, перетащу объект "manager" в private:
Код
C++ (Qt)
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
 
#include <memory>
 
#include <QObject>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetWorkAccessManager>
 
class Downloader : public QObject
{
   Q_OBJECT
 
   Downloader( )
   {
//        connect( m_reply, SIGNAL( finished( ) ),
//                 this, SLOT(replyFinished( ) ) );
   }
 
   void fetch( const QString &url )
   {
       m_reply.reset(m_manager->get( QNetworkRequest( QUrl( url ) ) ) );
   }
 
signals:
   void signalWithContent( QString * );
 
private slots:
   void replyFinished( )
   {
       QByteArray data = m_reply->readAll( );
       QString content( data );
       emit signalWithContent( &content );
   }
 
private:
   std::shared_ptr<QNetworkAccessManager> m_manager =
           std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
 
   std::shared_ptr<QNetworkReply> m_reply;
};
 
#endif // DOWNLOADER_H
 

У меня просто есть похожий код (правда он не совсем рабочий, но по другим причинам). Там тоже создаётся временный объект "manager":
Код
C++ (Qt)
#include "VKAuth.h"
#include <QNetworkRequest>
#include <QMessageBox>
 
VKAuth::VKAuth(QString app, QWidget* parent) : QWebView(parent)
{
 
   QObject::connect(this, SIGNAL(urlChanged(QUrl)),
                    SLOT(slotLinkChanged(QUrl))
                    );
   m_app = app;
   loadLoginPage();
}
 
void VKAuth::loadLoginPage(){
   QUrl url("https://oauth.vk.com/authorize");
 
   url.addQueryItem("client_id", m_app);
   url.addQueryItem("layout", "https://oauth.vk.com/blank.html");
   url.addQueryItem("display", "popup");
   url.addQueryItem("scope", "8");
   url.addQueryItem("response_type", "token");
 
   load(url);
}
 
void VKAuth::slotLinkChanged(QUrl url)
{
   if ("/blank.html" == url.path()) {
       QRegExp regexp("access_token=([^,]+)&expires_in=([^,]+)&user_id=([^,]+)");
 
       QString str= url.fragment();
 
       if( -1 != regexp.indexIn(str) ) {
           m_access_token = regexp.cap(1);
           m_expires_in = regexp.cap(2);
           m_user_id = regexp.cap(3);
           slotRequest();
       }
   }
   else if("/api/login_failure.html" == url.path()){
       emit unsuccess();
   }
}
 
void VKAuth::slotRequest() {
   QUrl request(QString("https://api.vk.com/method/%1.xml?").arg("friends.get"));
   request.addQueryItem("user_id", m_user_id);
   request.addQueryItem("fields", "online");
   request.addQueryItem("v", "5.2");
   request.addQueryItem("access_token", m_access_token);
 
   QNetworkAccessManager *manager = new QNetworkAccessManager(this);
   m_http = manager->get(QNetworkRequest(request));
   QObject::connect(m_http, SIGNAL(finished()), this, SLOT(slotDone()));
}
 
void VKAuth::slotDone() {
   QString russian = QString::fromUtf8(m_http->readAll());
   QDomDocument dom;
   QByteArray aByteArray = russian.toUtf8();
   if (!dom.setContent(aByteArray)) {
       QMessageBox::critical(this, tr("Error"), tr("Failed to parse the file into a DOM tree"));
       return;
   }
 
   emit success(dom);
   hide(); //hide this window
   m_http->close();
}
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 17:24
Ещё одна проблема. Помогите, пожалуйста. Понятия не имею, что не так. Выдаётся сообщение:
Цитировать
DownLoader.h:19: error: no matching function for call to 'Downloader::connect(std::shared_ptr<QNetworkReply>&, const char*, Downloader* const, const char*)'
                  this, SLOT(replyFinished( ) ) );

Код
C++ (Qt)
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
 
#include <memory>
 
#include <QObject>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetWorkAccessManager>
 
class Downloader : public QObject
{
   Q_OBJECT
 
   Downloader( )
   {
       connect( m_reply, SIGNAL( finished( ) ),
                this, SLOT( replyFinished( ) ) );
   }
 
   void fetch( const QString &url )
   {
       m_reply.reset(m_manager->get( QNetworkRequest( QUrl( url ) ) ) );
   }
 
signals:
   void signalWithContent( QString * );
 
private slots:
   void replyFinished( )
   {
       QByteArray data = m_reply->readAll( );
       QString content( data );
       emit signalWithContent( &content );
   }
 
private:
   std::shared_ptr<QNetworkAccessManager> m_manager =
           std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
 
   std::shared_ptr<QNetworkReply> m_reply;
};
 
#endif // DOWNLOADER_H
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: kambala от Июнь 18, 2014, 18:09
В исходниках я нашёл:
Код
C++ (Qt)
QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
{
   return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
}
 

Но мне это не о чём не говорит...
можно еще и в метод createRequest() было заглянуть :)
Я думал, что нам объект "manager" нужен только чтобы "m_reply" инициализировать. Разве нет?
разве нет. почитай про класс менеджера.
У меня просто есть похожий код (правда он не совсем рабочий, но по другим причинам). Там тоже создаётся временный объект "manager"
там обычный указатель, который не умирает по выходе из области видимости (но есть утечка памяти пока объект VKAuth будет жить)

а для чего тебе вообще сохранять этот QNetworkReply? у менеджера же есть сигнал, в который QNetworkReply передается.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 18:40
kambala, Спасибо! :)

Вот ответ на второй вопрос:
Код:
    Downloader( )
    {
        connect( m_reply.get(), SIGNAL( finished( ) ),
                 this, SLOT( replyFinished( ) ) );
    }

P.S. Правда я пока не понял, почему работает... Здесь подсказали: http://www.qtcentre.org/threads/59501-Using-std-shared_ptr-for-Qt-objects?p=264172#post264172


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 18:58
P.S. Правда я пока не понял, почему работает...
А теперь понял. Переменная m_reply имеет тип std::shared_ptr<QNetworkReply>. Чтобы получить указатель на QNetworkReply надо вызвать метод get класса std::shared_ptr: http://www.cplusplus.com/reference/memory/shared_ptr/get/


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 20:05
Приложение дописал, но как раз в том модуле ошибка. Невозможно соединить сигнал и слот. Почему-то m_reply.get( ) возвращает null, если я правильно понял.

Цитировать
QObject::connect: Cannot connect (null)::finished( ) to Downloader::replyFinished( )
QObject::connect: Cannot connect (null)::QNetworkReply::downloadProgress( qint64 bytesReceived, qint64 bytesTotal ) to Downloader::slotDownloadProgress(qint64 bytesReceived, qint64 bytesTotal )
QObject::connect: No such slot QProgressBar::replyProgress( qint64 bytesReceived, qint64 bytesTotal ) in D:/Qt/QtPortfolio/0009_ParserHtmlRGB/ParserHtmlRGB/Dialog.cpp:19
QObject::connect:  (receiver name: 'progressBar')

Код
C++ (Qt)
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
 
#include <memory>
 
#include <QObject>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetWorkAccessManager>
 
class Downloader : public QObject
{
   Q_OBJECT
 
public:
   Downloader( )
   {
       connect( m_reply.get( ), SIGNAL( finished( ) ),
                this, SLOT( replyFinished( ) ) );
       connect( m_reply.get( ), SIGNAL( QNetworkReply::downloadProgress( qint64 bytesReceived, qint64 bytesTotal ) ),
                this, SLOT( slotDownloadProgress(qint64 bytesReceived, qint64 bytesTotal ) ) );
   }
 
   void fetch( const QString &url )
   {
       m_reply.reset(m_manager->get( QNetworkRequest( QUrl( url ) ) ) );
   }
 
signals:
   void signalWithContent( QString * );
   void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
 
private slots:
   void replyFinished( )
   {
       QByteArray data = m_reply->readAll( );
       QString content( data );
       emit signalWithContent( &content );
   }
 
   void slotDownloadProgress( qint64 bytesReceived, qint64 bytesTotal )
   {
       emit downloadProgress( bytesReceived, bytesTotal );
   }
 
private:
   std::shared_ptr<QNetworkAccessManager> m_manager =
           std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
 
   std::shared_ptr<QNetworkReply> m_reply;
};
 
#endif // DOWNLOADER_H
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 18, 2014, 20:13
А что вас удивляет?
Вы коннект делаете в конструкторе, а объект получаете в методе fetch.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 20:20
Спасибо большое! Я как раз так попробовал - работает! Правда несколько удивляет. Получается, что конекты всегда надо делать только после того, как объекты полностью инициализирован?

Код
C++ (Qt)
   void fetch( const QString &url )
   {
       m_reply.reset(m_manager->get( QNetworkRequest( QUrl( url ) ) ) );
       connect( m_reply.get( ), SIGNAL( finished( ) ),
                this, SLOT( replyFinished( ) ) );
       connect( m_reply.get( ), SIGNAL( QNetworkReply::downloadProgress( qint64 bytesReceived, qint64 bytesTotal ) ),
                this, SLOT( slotDownloadProgress(qint64 bytesReceived, qint64 bytesTotal ) )     );
   }
 


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 18, 2014, 20:41
Ещё в моём коде надо заменить:
Код
C++ (Qt)
connect( m_reply.get( ), SIGNAL( QNetworkReply::downloadProgress( qint64 bytesReceived, qint64 bytesTotal ) ),
                this, SLOT( slotDownloadProgress(qint64 bytesReceived, qint64 bytesTotal ) ) );
 

На этот код:
Код
C++ (Qt)
connect( m_reply.get( ), SIGNAL( downloadProgress( qint64, qint64 ) ),
                this, SLOT( slotDownloadProgress(qint64, qint64 ) ) );
 

И ещё вопрос не совсем по теме. Этот модуль скачивает содержимое HTML страницы и я хотел бы видеть процесс скачивания, но у меня bytesTotal  всегда равен -1. Что делать?


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 19, 2014, 08:23
я не понял, а зачем в make_shared new?
Код:
        std::shared_ptr<QNetworkAccessManager> manager =
                std::make_shared<QNetworkAccessManager>( new QNetworkAccessManager( this ) );

make_shared специально создан для того, чтобы не надо было вызывать new и не было ненужной аллокации.

Нужно писать так.
Код:
std::shared_ptr<QNetworkAccessManager> manager =
                std::make_shared<QNetworkAccessManager>(this);


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 19, 2014, 08:49
Спасибо Вам огромное! Вы мне показали и как инициализировать shared_ptr с помощью reset и как правильно инициализировать с помощью std::make_shared :)


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Igors от Июнь 19, 2014, 10:14
Читал-читал, так и не понял чему это все посвящено :)
Код
C++ (Qt)
private:
   QNetworkReply * m_reply;
};
Ну и в конструкторе инициализировать, в деструкторе сделать delete. Не вижу какие тут возможны (у)течки. Может кайф в том что шареный m_reply можно куда-то отдать а сам класс Downloader уже удалить. Но по приведенному коду не видно где это обыгрывается. Выходит, так, "на всякий случай" - засорить код и пустить пыль в глаза.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 19, 2014, 10:17
Igors, смысл в том, чтобы везде использовать shared_ptr вместо обычных указателей.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: carrygun от Июнь 19, 2014, 10:25
Igors, смысл в том, чтобы везде использовать shared_ptr вместо обычных указателей.

А в чем от этого смысл?


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 19, 2014, 10:31
Igors, смысл в том, чтобы везде использовать shared_ptr вместо обычных указателей.
А в чем от этого смысл?
К примеру, чтобы не бояться забыть написать delete. Есть и другие ситуации, когда, к примеру, из-за исключений могут происходить утечки, когда дело до delete не доходить. Вообщем, один раз приучить себя использовать shared_ptr везде и не париться. Такое моё мнение.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Bepec от Июнь 19, 2014, 10:34
Гениально :D


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Igors от Июнь 19, 2014, 10:54
К примеру, чтобы не бояться забыть написать delete. Есть и другие ситуации, когда, к примеру, из-за исключений могут происходить утечки, когда дело до delete не доходить. Вообщем, один раз приучить себя использовать shared_ptr везде и не париться.
Нехорошо что коду придается смысл которого нет. Увидев объявление шаред читающий имеет ввиду типа "внимание, этот указатель может жить и без объекта" (где он член), и такая ситуация может быть непростой. А если все без разбора шаред - понять логику гораздо труднее.

Такое моё мнение.
Не надо тупенько передирать чужие приемы, мол, вот опытный программист везде юзает шаред - и я буду! Свое мнение надо еще иметь.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Bepec от Июнь 19, 2014, 11:05
Самое весёлое потом начнётся. Когда надо будет держать пару десятков умных указателей.
Это выбешивает почище синего экрана каждые 5 минут :)

PS не спорю, что это признак "хорошей" архитектуры, но и тут не лучше :D


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: Old от Июнь 19, 2014, 11:08
Самое весёлое потом начнётся. Когда надо будет держать пару десятков умных указателей.
Какие пару десятков? Их тысячи прямо сейчас держатся и кроме спокойствия (глядя на потребление памяти серверами) ничего не приносят. :)


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 19, 2014, 11:48
Igors, смысл в том, чтобы везде использовать shared_ptr вместо обычных указателей.
А в чем от этого смысл?
К примеру, чтобы не бояться забыть написать delete. Есть и другие ситуации, когда, к примеру, из-за исключений могут происходить утечки, когда дело до delete не доходить. Вообщем, один раз приучить себя использовать shared_ptr везде и не париться. Такое моё мнение.


Почему тогда shared_prt, а не scoped_ptr? scoped_ptr менее тяжеловесен и не ведет подсчет ссылок.  Поскольку твой объект ни куда не передается и не копируется, то достаточно и scoped_ptr. Igors правильно сказал, если тебе требуется, чтобы член-класса жил без объекта данного класса, тогда используй shared, а если ты не хочешь писать new/delete и следить за правильным созданием/удалением объектов, то тогда тебе хватит scoped_ptr (он же auto_ptr в С++11, он же unique_ptr в С++03)


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: vizir.vs от Июнь 19, 2014, 12:00
Самое весёлое потом начнётся. Когда надо будет держать пару десятков умных указателей.
Это выбешивает почище синего экрана каждые 5 минут :)

PS не спорю, что это признак "хорошей" архитектуры, но и тут не лучше :D

По мне, так RAII очень полезная идиома.


Название: Re: Использование std::shared_ptr для Qt объектов
Отправлено: 8Observer8 от Июнь 23, 2014, 09:57
Судя по тексту из этого списка: http://www.cplusplus.com/reference/memory/ "Automatic Pointer [deprecated]" => std::auto_ptr - "резко осуждается"

Вместо него советуют использовать std::unique_ptr из C++11: http://www.cplusplus.com/reference/memory/unique_ptr/
Цитировать
Note: This class template is deprecated as of C++11. unique_ptr is a new facility with a similar functionality, but with improved security (no fake copy assignments), added features (deleters) and support for arrays. See unique_ptr for additional information.

(он же auto_ptr в С++11, он же unique_ptr в С++03)
Кстати, здесь наоборот :)

Как я понял, scoped_ptr - это из библиотеки Boost. А std::unique_ptr, для моего примера, будет наиболее подходящим:
Код
C++ (Qt)
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
 
#include <memory>
#include <QObject>
#include <QString>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
 
class Downloader : public QObject
{
public:
 
   Downloader( )
   {
       m_manager = std::unique_ptr<QNetworkAccessManager>( new QNetworkAccessManager( this ) );
   }
 
   void fetch( const QString &url )
   {
       m_reply.reset( m_manager->get( QNetworkRequest( QUrl( url ) ) ) );
       connect( m_reply.get( ), 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:
   std::unique_ptr<QNetworkReply> m_reply;
   std::unique_ptr<QNetworkAccessManager> m_manager;
};
 
#endif // DOWNLOADER_H
 

P.S Единственное неудобство, то что не срабатывает подсказка с std::unique_ptr в Creator'е. К примеру, с std::shared_ptr работает вставка "finished( )" если я набрал "fini" и нажал "Ctrl+Space", а с std::unique_ptr - нет:
Код
C++ (Qt)
connect( m_reply.get( ), SIGNAL( fini ) );
 


Название: Re: [Решено] Использование std::shared_ptr и std::unique_ptr c Qt объектами
Отправлено: vizir.vs от Июнь 23, 2014, 13:29
у Qt так же есть свои умные указатели. А  по поводу auto_ptr и unique_ptr, я к бустовским умным указателям уже привык и stl-кие почти не использую.