Название: [Решено] Использование 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)...); } ^ Код
Название: 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
Что по вашему делает эта строка? Код
Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: 8Observer8 от Июнь 18, 2014, 15:17 Если я не ошибаюсь, то QNetworkReply является абстрактным классом, у него чистая виртуальная функция abort. Нельзя создавать объекты класса QNetworkReply. Хм.. и правда. А почему мы тогда можем создавать объект этого класса через указатель? Как в этом коде:Код
А вот так нельзя: Код [/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 А почему так можно:
Код
А так нельзя: Код
Название: 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 В исходниках я нашёл:
Код
Но мне это не о чём не говорит... Хорошо, допустим, что get() возвращает указатель на объект класса потомка от QNetworkReply. Как узнать, какого потомка мне написать вместо вопросиков: Код
Название: 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
Код:
Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: 8Observer8 от Июнь 18, 2014, 16:06 Как узнать, какого потомка мне написать вместо вопросиков: Здесь не нужен make_shared. Объект ответа уже сконструирован внутри get.Проблема в том, что я не могу написать так: Код
У меня переменная 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 Что значит нельзя инициализировать в секции приват? А ведь и вправду можно:Код Но в моём случае это не подходит. У меня сначала создаётся переменная: std::shared_ptr<QNetworkAccessManager> manager. А потом m_reply. Смотри мой предыдущий ответ. Я как раз под него код переписывал и пробовал. Вот так и буду делать. Объявлять переменную:Код
А потом инициализировать: Код
Спасибо всем огромное! Я ещё нашёл, что так нельзя писать: Код
Так как утечки памяти возможны в случае исключений. И вроде два раза место выделяется. Я тонкости ещё не знаю... Вот так правильно: Код
Вот так исправил: Код
Название: 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:
Код
У меня просто есть похожий код (правда он не совсем рабочий, но по другим причинам). Там тоже создаётся временный объект "manager": Код
Название: 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( ) ) ); Код
Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: kambala от Июнь 18, 2014, 18:09 В исходниках я нашёл: можно еще и в метод createRequest() было заглянуть :)Код
Но мне это не о чём не говорит... Я думал, что нам объект "manager" нужен только чтобы "m_reply" инициализировать. Разве нет? разве нет. почитай про класс менеджера.У меня просто есть похожий код (правда он не совсем рабочий, но по другим причинам). Там тоже создаётся временный объект "manager" там обычный указатель, который не умирает по выходе из области видимости (но есть утечка памяти пока объект VKAuth будет жить)а для чего тебе вообще сохранять этот QNetworkReply? у менеджера же есть сигнал, в который QNetworkReply передается. Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: 8Observer8 от Июнь 18, 2014, 18:40 kambala, Спасибо! :)
Вот ответ на второй вопрос: Код: Downloader( ) 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') Код
Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: Old от Июнь 18, 2014, 20:13 А что вас удивляет?
Вы коннект делаете в конструкторе, а объект получаете в методе fetch. Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: 8Observer8 от Июнь 18, 2014, 20:20 Спасибо большое! Я как раз так попробовал - работает! Правда несколько удивляет. Получается, что конекты всегда надо делать только после того, как объекты полностью инициализирован?
Код
Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: 8Observer8 от Июнь 18, 2014, 20:41 Ещё в моём коде надо заменить:
Код
На этот код: Код
И ещё вопрос не совсем по теме. Этот модуль скачивает содержимое HTML страницы и я хотел бы видеть процесс скачивания, но у меня bytesTotal всегда равен -1. Что делать? Название: Re: Использование std::shared_ptr для Qt объектов Отправлено: vizir.vs от Июнь 19, 2014, 08:23 я не понял, а зачем в make_shared new?
Код: std::shared_ptr<QNetworkAccessManager> manager = make_shared специально создан для того, чтобы не надо было вызывать new и не было ненужной аллокации. Нужно писать так. Код: std::shared_ptr<QNetworkAccessManager> manager = Название: 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 Читал-читал, так и не понял чему это все посвящено :)
Код Ну и в конструкторе инициализировать, в деструкторе сделать 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 вместо обычных указателей. А в чем от этого смысл?Название: 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 вместо обычных указателей. А в чем от этого смысл?Почему тогда 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, для моего примера, будет наиболее подходящим: Код
P.S Единственное неудобство, то что не срабатывает подсказка с std::unique_ptr в Creator'е. К примеру, с std::shared_ptr работает вставка "finished( )" если я набрал "fini" и нажал "Ctrl+Space", а с std::unique_ptr - нет: Код
Название: Re: [Решено] Использование std::shared_ptr и std::unique_ptr c Qt объектами Отправлено: vizir.vs от Июнь 23, 2014, 13:29 у Qt так же есть свои умные указатели. А по поводу auto_ptr и unique_ptr, я к бустовским умным указателям уже привык и stl-кие почти не использую.
|