LINUX.ORG.RU

Адаптация кода для smart pointers

 , , smart pointers


0

4

Привет всем.

Такая ситуация: хочу уйти от использования в коде raw pointers, к сожалению, многие функции Qt, с которой я должен работать, не принимают все эти *_ptr, а только указатели как они есть. Приходится обращаться при этом к методу get, что как я читал - плохо, чтобы получить искомое. Есть ли другой способ и умные указатели использовать и правильно преобразовывать их тип в нужный при передаче параметром?

Всем спасибо.

★★★★★

Последнее исправление: LongLiveUbuntu (всего исправлений: 1)

А о каком конкретно указателе речь ? А то тот-же шаред поинтер имеет все необходимые перегрузки для нормальной работы.

DawnCaster ★★
()
Ответ на: комментарий от DawnCaster

Ну вот смотри, метод connect ждёт аргумент QObject*, я могу передать ему объект типа shared_ptr<QObject> без риска утечки памяти?

LongLiveUbuntu ★★★★★
() автор топика

Я могу ошибаться, но в Qt как будто бы для наследников QObject принято использовать немного другую модель управления памятью, а именно - модель владения. Т.е. ты руками удаляешь только корневой объект, а остальным - должен назначить родителя.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Вроде можно и руками дочерние об’екты удалить. Главное, что у каждого есть родительский об’ект, и при его удалении, рекурсивно удаляются все дочерние об’екты. А при ручном удалении дочернего он просто выписывается из списка дочерних в своем родителе при деструкции:

https://riptutorial.com/qt/example/22800/qobject-lifetime-and-ownership

seiken ★★★★★
()
Последнее исправление: seiken (всего исправлений: 2)
Ответ на: комментарий от LongLiveUbuntu

Нет, так, конечно, не получится. Можно передать ему указатель который ссылается на ресурс управляемый смарт поинтером (там должно быть неявное преобразование в указатель о чем я писал ранее). И все будет работать пока вы можете гарантировать что ваш смарт поинтер переживёт обьект с методом connect которому вы передаете указатель. Но смысл в использовании умных указателей в таком случае теряется.

DawnCaster ★★
()
Последнее исправление: DawnCaster (всего исправлений: 3)

Лень вызвать get(), в этом дело? Ну можно обёртку закостылить:

#include <memory>

template <typename T>
class My_ptr : public std::unique_ptr<T>
{
public:
	using std::unique_ptr<T>::unique_ptr; 
	operator T*() {return this->get();}
};

int main()
{
	My_ptr<int> p(new int);
	int *i = p;
}

Только учти про то, управляет ли сам QT памятью, которую ты передаешь, уже выше сказали об этом. Я QT никода ни использовал.

pavlick ★★
()

Во-первых, у Qt уже есть свои smart pointers – QSharedPointer и компания. Где они нужны в API — Qt уже их принимает.

Во-вторых, shared pointers моделируют совместное владение объектом. У Qt уже модель владения QObjects типа виджетов, и она не совместная — и не совместимая с shared pointers.

В общем, нужно думать, когда какие указатели нужны и полезны.

ilammy ★★★
()

Берите std::unique_ptr, можно вызвать метод release чтобы передать владение в обычный raw-указатель. Наоборот тоже легко делается.

X512 ★★★★★
()
Ответ на: комментарий от scientistpython

Просто я прогнал код через clang-tidy, ну, тут оно и повылезало.

Хотя да, Qt слишком самобытная штука.

LongLiveUbuntu ★★★★★
() автор топика
Ответ на: комментарий от ilammy

Где они нужны в API — Qt уже их принимает

Нихрена. Даже connect принимает сырые, и примерно всё остальное.

У Qt уже модель владения QObjects типа виджетов, и она

… не нужна в 21-м веке. Всё отлично делается на смартпойнтерах, хоть Qt-шных, хоть стандартных.

anonymous
()

что как я читал - плохо

Либо ты не понял, либо автор. В данном случае get - то что нужно.

Конечно, каждый раз надо задуматься про время жизни объекта.

anonymous
()
Ответ на: комментарий от DawnCaster

Но смысл в использовании умных указателей в таком случае теряется

Не теряется. При удалении объекта, connect’ы на него, будь то сигналом или слотом, удаляются автоматически.

anonymous
()
Ответ на: комментарий от anonymous

Я не в курсе что там у QT в кишках, очень давно уже в нём не работал.

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

В нормальном случае, мы должны проследить что-бы наш умный указатель не самоуничтожился пока внешний код не перестанет использовать переданный в него обычный указатель. Полагаться на какую-то умную логику внутри внешнего кода - в общем случае, это bad practice, потенциальный баг и UB. Не надо так делать.

Может QT со своим постпроцессором MOC что-то с этим делает, может особым образом объявленные умные указатели или другие объекты в каких-то местах в классах QT как-то особым образом обрабатываюся, я хз. Я говорил про общий случай, я не в курсе даже что там делает connect у QT. Но полагаться на внешнюю логику в таких случаях не рекомендуется обычно.

DawnCaster ★★
()
Последнее исправление: DawnCaster (всего исправлений: 2)
Ответ на: комментарий от DawnCaster

Конкретно с коннектами - это документированное поведение, и лучше не сделаешь, и нормально работает. Опыта много.

Альтернатива - отказываться от смартпойнтеров и лепить deleteLater в событиях. Вряд ли проще.

А в общем случае всё так, да.

anonymous
()

Всё просто: сырой указатель рассматривай как невладеющий. Qt не принимает на себя управление временем жизни объектов по указателям в подавляющем числе случаев, единственное исключение, которое приходит на ум - когда указывается парент у QObject, но это элементарно: просто никогда его не указывай.

Метод connect, естественно, удалять или перемещать объект по ссылке не будет, его же можно вызывать и для объектов на стеке.

И это общая практика в современном С++ - избегать сырых указателей любой ценой не нужно, но они всегда не владеющие.

unC0Rr ★★★★★
()
Последнее исправление: unC0Rr (всего исправлений: 1)
Ответ на: комментарий от anonymous

можно нуллптр указать, кувиджеты вообще окном становятся в таком раскладе.

deep-purple ★★★★★
()
Ответ на: комментарий от pon4ik

Я могу ошибаться, но в Qt как будто бы для наследников QObject принято использовать немного другую модель управления памятью, а именно - модель владения. Т.е. ты руками удаляешь только корневой объект, а остальным - должен назначить родителя.

Этот принцип не работает, например, с QLayer и его производными? QLayer получает указатель на содержащийся в нем объект, но не становится его владельцем. Щас уже не вспомню, но и у некоторых других объектов видел такое поведение. Да, оно описано в документации, но принцип имеет для некоторых ситуаций нюансы, которые неочевидны.

Xintrea ★★★★★
()
Ответ на: комментарий от Xintrea

Ну так QLayer не владеет виджетами, виджетами владеет виджет на котором эти виджеты расположенны, так что пример не засчитывается.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

А почему бы не соблюдать иерархию, и виджету владеть QLayer, который в свою очередь владеет виджетами?

Xintrea ★★★★★
()
Ответ на: комментарий от Xintrea

Так layer может легко заменяться в процессе работы приложения, прикажешь виджеты и их состояние пересоздавать?

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Резонно, правда в моей практике такого не встречалось.

Xintrea ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.