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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QScopedPointer  (Прочитано 14075 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Октябрь 17, 2018, 08:28 »

Добрый день

QScopedPointer (или его std аналог) как член класса довольно удобен, пусть и не делает великих дел. Но вот беда - класс сразу становится некопируемым по умолчанию. Объявлять шаред явно нехорошо, ведь ничего шарить не собирался, скорее наоборот. Какие есть др решения?

Спасибо
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #1 : Октябрь 17, 2018, 10:24 »

QScopedPointer (или его std аналог) как член класса довольно удобен, пусть и не делает великих дел. Но вот беда - класс сразу становится некопируемым по умолчанию. Объявлять шаред явно нехорошо, ведь ничего шарить не собирался, скорее наоборот. Какие есть др решения?
Так вы определитесь, нужно копирование или нет?
Этот указатель владеет ресурсом, на который указывает. Вы копируете объект с таких указателем, кто после этого должен владеть этим ресурсом: исходный объект или его копия?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #2 : Октябрь 17, 2018, 16:13 »

Если необходим указатель, который ведет себя как экземпляр объекта, то не припомню такого в std или Qt.
Но его можно легко реализовать как-то так (код не проверял, но вроде должен работать).

Код
C++ (Qt)
template< typename _Type >
class InstancePtr
{
   using ThisType = InstancePtr< _Type >;
 
   using RawPtr = _Type *;
   using RawRef = _Type &;
   using ConstRawPtr = const _Type *;
   using ConstRawRef = const _Type &;
 
   RawPtr m_pointer;
 
public:
   template < typename ... _Arguments >
   InstancePtr ( _Arguments && ... arguments )
       : m_pointer( new _Type( ::std::forward< _Arguments >( arguments ) ... ) )
   {}
 
   InstancePtr ( ThisType && other )
       : m_pointer( ::std::forward< PointerType >( other.m_pointer ) )
   {
       other.m_pointer = nullptr;
   }
 
   InstancePtr ( const ThisType & other )
       : InstancePtr( *other.m_pointer )
   {}
 
   ~InstancePtr () { delete m_pointer; }
 
   RawRef operator * () { return *m_pointer; }
   RawPtr operator -> () { return m_pointer; }
   ConstRawRef operator * () const { return *m_pointer; }
   ConstRawPtr operator -> () const { return m_pointer; }
};
 
« Последнее редактирование: Октябрь 17, 2018, 18:29 от ssoft » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Октябрь 17, 2018, 21:33 »

Какие есть др решения?

мувать
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Октябрь 18, 2018, 08:30 »

Но его можно легко реализовать как-то так (код не проверял, но вроде должен работать).
Верю Улыбающийся Но тут эффект что я не раз наблюдал: нужно именно "стандартный" (вумный) указатель, хочет человек или нет, а справочник откроет, жизнь заставит. А "велик" может быть самый распрекрасный, но.. другим-то надо в него вникать, да еще и с нуля и без доки, это вызывает недовольство.

Типовая ситуевина - да, вот есть член которого "может и не быть" (isNull), т.е. scoped по смыслу подходит, но нужно класть экземпляры класса в контейнер. Приходится перекрывать конструктор/оператор копирования, хотелось бы без этого.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #5 : Октябрь 18, 2018, 08:50 »

мувать

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

Мувать нужно и в том и в другом случае, собственно, как и копировать. В случае с указателем выше move дешевле, копирование дороже).
Всяких указателей можно наделать сколько угодно много, обеспечить, например, с помощью них потокобезопасность (https://habr.com/post/328348/).
Главное - сформулировать ожидаемое поведение и вперед...)

Верю Улыбающийся Но тут эффект что я не раз наблюдал: нужно именно "стандартный" (вумный) указатель, хочет человек или нет, а справочник откроет, жизнь заставит. А "велик" может быть самый распрекрасный, но.. другим-то надо в него вникать, да еще и с нуля и без доки, это вызывает недовольство.

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

Поведение, которое необходимо в задаче, не обеспечивается с помощью стандартных средств.
Прежде всего, по причине, что это указатели, и ожидается что они ведут себя как указатели, а не экземпляр объекта, на который они указывают.
Поэтому использование дополнительного класса здесь вполне оправдано, и не является "велосипедом" по отношению к стандартным, так как реализует совершенно другое поведение.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #6 : Октябрь 18, 2018, 08:57 »

Типовая ситуевина - да, вот есть член которого "может и не быть" (isNull), т.е. scoped по смыслу подходит, но нужно класть экземпляры класса в контейнер. Приходится перекрывать конструктор/оператор копирования, хотелось бы без этого.

Это ещё один сценарий поведения для OptionalPtr ))).
Вообще, это тема умных указателей достаточно обширная и вполне можно еще раз ее обсудить подробнее, если есть желание).
Последний раз она затрагивалась здесь http://www.prog.org.ru/index.php?topic=32109
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #7 : Октябрь 18, 2018, 10:23 »

Типовая ситуевина - да, вот есть член которого "может и не быть" (isNull), т.е. scoped по смыслу подходит, но нужно класть экземпляры класса в контейнер. Приходится перекрывать конструктор/оператор копирования, хотелось бы без этого.

Вы так и не ответили на вопрос Old'а: нужно копирование или нет? Опять все догадываться должны, что Вы там себе придумали? Чтобы покласть объекты в контейнер, не обязательно их копировать, можно перемещать.

Допустим таки надо копировать.

1. Если совсем лень, можно попробовать использовать std::optional. Но затея не из лучших.
2. Написать метод, который копирует объект по указателю в том смысле, в каком это нужно для заданного класса. Навскидку:
Код
C++ (Qt)
std::unique_ptr<SomeClass> makeCopy(const std::unique_ptr<SomeClass>& from);
Соответственно придётся написать конструкторы/операторы копирования. И лучше использовать std::unique_ptr, чем QScopedPointer.
3. Написать обертку с нужным поведением, как предлагает ssoft.
Записан

Пока сам не сделаешь...
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #8 : Октябрь 18, 2018, 10:32 »

Вы так и не ответили на вопрос Old'а: нужно копирование или нет? Опять все догадываться должны, что Вы там себе придумали?
Это по тому, что о таких мелочах как "владения" никто не думал. Добавил умных указателей, перестало компилироваться - пришел спросить что делать. Улыбающийся
« Последнее редактирование: Октябрь 18, 2018, 10:35 от Old » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #9 : Октябрь 18, 2018, 11:07 »

Это по тому, что о таких мелочах как "владения" никто не думал. Добавил умных указателей, перестало компилироваться - пришел спросить что делать. Улыбающийся

Ну хоть спрашивать начинают, и то хорошо. А то обычный подход: "Не получается с unique_ptr? Меняем на shared_ptr и ... в продакшн." Улыбающийся.
Записан

Пока сам не сделаешь...
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #10 : Октябрь 18, 2018, 11:18 »

QScopedPointer (или его std аналог) как член класса довольно удобен, пусть и не делает великих дел. Но вот беда - класс сразу становится некопируемым по умолчанию. Объявлять шаред явно нехорошо, ведь ничего шарить не собирался, скорее наоборот. Какие есть др решения?
Так вы определитесь, нужно копирование или нет?
Этот указатель владеет ресурсом, на который указывает. Вы копируете объект с таких указателем, кто после этого должен владеть этим ресурсом: исходный объект или его копия?

ИМХО, было бы приемлемо создание копий таких поинтеров, но с условием, что по умолчанию класс-копия не уничтожает ресурс при своем уничтожении (если при копировании это не указано явно). Ну то есть обычный use case - это передать "умный" указатель куда-то во временную функцию. При этом с ресурсом как правило ничего трагичного происходить не планируется.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Октябрь 18, 2018, 12:10 »

Всяких указателей можно наделать сколько угодно много, обеспечить, например, с помощью них потокобезопасность (https://habr.com/post/328348/).
Главное - сформулировать ожидаемое поведение и вперед...)
Вот именно, "наделать" можно, но дальше велика это никуда не пойдет. С интересом прочитал статью, оказывается можно как-то хитро привязаться к оператору ->, не знал. Да, познавательно, но.. на этом все и кончается - практически никто и никогда таких огородов городить не будет. Слишком сложно по сравнению с достигаемым рез-том. Ну и вообще
Цитировать
int & a = container[ i ];
Если контейнеры позволяют такую конструкцию, то они по своей природе не могут быть "потокобезопасны", т.к. время жизни ссылки неизвестно и др нитки прорваться не смогут. Можно создать какой-то ограниченный вариант, это интересно, хотя и жить не будет. C'est la vie

1. Если совсем лень,
...
Вы сказали много интересного и нового, но то что интересно - не ново, а то что ново - не интересно" Улыбающийся

Ну хоть спрашивать начинают, и то хорошо. А то обычный подход: "Не получается с unique_ptr? Меняем на shared_ptr и ... в продакшн." Улыбающийся.
Мне известно что нормального стандартного решения здесь нет, и обвинять QScopedPointer нет оснований. В конце-концов член "просто указатель" (от которого сейчас модно воротить нос) тоже потребует перекрытия копирования/присваивания - но никаких ошибок не выдаст и загнется в runtime, в этом плане QScopedPointer если и не лучше, то корректнее.

ИМХО, было бы приемлемо создание копий таких поинтеров, но с условием, что по умолчанию класс-копия не уничтожает ресурс при своем уничтожении (если при копировании это не указано явно). Ну то есть обычный use case - это передать "умный" указатель куда-то во временную функцию. При этом с ресурсом как правило ничего трагичного происходить не планируется.
Часто заводят флажок с именем типа "shouldDelete" Улыбающийся А отдавать - да. "голый", лучшего не видно

Что касается "сущностей" и.т.п. Ну вот есть "просто член класса", агрегатом, не указатель  - он почему-то прекрасно копируется. Интуитивно QScopedPointer - такой же член, который однако может быть и null. И что с того - почему он не копируется? Чему это противоречит? Оригинал владеет своим экземпляром, копия - своим, "уникальность" соблюдена. Как-то нынешнее поведение неестественно  Улыбающийся
« Последнее редактирование: Октябрь 18, 2018, 12:14 от Igors » Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #12 : Октябрь 18, 2018, 12:33 »

Вы сказали много интересного и нового, но то что интересно - не ново, а то что ново - не интересно" Улыбающийся

Т.е. Вы сами всё знаете. Отлично Улыбающийся.

Что касается "сущностей" и.т.п. Ну вот есть "просто член класса", агрегатом, не указатель  - он почему-то прекрасно копируется. Интуитивно QScopedPointer - такой же член, который однако может быть и null. И что с того - почему он не копируется? Чему это противоречит? Оригинал владеет своим экземпляром, копия - своим, "уникальность" соблюдена. Как-то нынешнее поведение неестественно  Улыбающийся

Напишите про это в комитет по стандартизации С++, а то "мужики-то не знают" Улыбающийся.
Записан

Пока сам не сделаешь...
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #13 : Октябрь 18, 2018, 12:38 »

ИМХО, было бы приемлемо создание копий таких поинтеров, но с условием, что по умолчанию класс-копия не уничтожает ресурс при своем уничтожении (если при копировании это не указано явно). Ну то есть обычный use case - это передать "умный" указатель куда-то во временную функцию. При этом с ресурсом как правило ничего трагичного происходить не планируется.

А пожалуйста.
Записан

Пока сам не сделаешь...
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #14 : Октябрь 18, 2018, 14:41 »

Всяких указателей можно наделать сколько угодно много, обеспечить, например, с помощью них потокобезопасность (https://habr.com/post/328348/).
Главное - сформулировать ожидаемое поведение и вперед...)
Вот именно, "наделать" можно, но дальше велика это никуда не пойдет.

Почему велик-то? В программе же объявляются типы для хранения данных и формирования нужного поведения.
Это такой же пользовательский тип, как и все другие. Назовите его не указателем (тем более, что желаемая сущность им и не является), а HeapInstance или HeapOptional, например.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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