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

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

Страниц: 1 2 [3]   Вниз
  Печать  
Автор Тема: std::map<..., unique_ptr> инициализация  (Прочитано 21491 раз)
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #30 : Февраль 07, 2017, 20:21 »

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

Ещё хорошо продуманные wrapper не позволяют ерунду в коде писать Улыбающийся. По крайней мере всячески этому сопротивляются, и заставляют думать, где какое владение использовать и какие типы связей должны быть между объектами на уровне модели. И подход "скомпились уже и отстань от меня", как можно было писать в случае с голыми указателями, с wrapper уже не прокатывает Улыбающийся.

А текущие unique_ptr, shared_ptr, weak_ptr зачастую используются как некий частный случай сборщика мусора и не более.
Записан

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

Сообщений: 4349



Просмотр профиля
« Ответ #31 : Февраль 08, 2017, 00:58 »

В зависимости от конкретного случая вполне оправдано использование инструментов в любом сочетании

shared/raw, unique/raw
Никогда не оправдано. Только вернули raw - полностью потеряли контроль над объектом.

shared/my_any
Это вообще как?
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #32 : Февраль 08, 2017, 07:30 »

shared/my_any
Это вообще как?
Подозреваю, что так
Код
C++ (Qt)
my_any(shared.get());
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #33 : Февраль 08, 2017, 08:26 »

Ещё хорошо продуманные wrapper не позволяют ерунду в коде писать Улыбающийся. По крайней мере всячески этому сопротивляются, и заставляют думать, где какое владение использовать и какие типы связей должны быть между объектами на уровне модели. И подход "скомпились уже и отстань от меня", как можно было писать в случае с голыми указателями, с wrapper уже не прокатывает Улыбающийся.
Так-то оно так, но для объявления. А если указатель подается в ф-цию/метод, то в подавляющем большинстве случаев никакой умности не требуется. Сравним
Код
C++ (Qt)
void DoSomething( const SomeData * data );
void DoSomething( shared_ptr<SomeData> data );
 
Теперь (2-я строка) ф-ция не сможет удалить данные! И гарантируется что data будет жить даже если вызывающий удален! (актуально при multi-threading). Не очень-то веские причины/резоны. Выходит из заявления shared_ptr ничего по существу не следует, и на него можно не обращать внимания. Зачем тогда заявлять?
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #34 : Февраль 08, 2017, 12:51 »

Так-то оно так, но для объявления. А если указатель подается в ф-цию/метод, то в подавляющем большинстве случаев никакой умности не требуется. Сравним
Код
C++ (Qt)
void DoSomething( const SomeData * data );
void DoSomething( shared_ptr<SomeData> data );
 
Теперь (2-я строка) ф-ция не сможет удалить данные! И гарантируется что data будет жить даже если вызывающий удален! (актуально при multi-threading). Не очень-то веские причины/резоны. Выходит из заявления shared_ptr ничего по существу не следует, и на него можно не обращать внимания. Зачем тогда заявлять?

Как раз и следует:
Теперь (2-я строка) ф-ция не сможет удалить данные! И гарантируется что data будет жить даже если вызывающий удален! (актуально при multi-threading).

И это достаточно веские резоны. Если на этапе проектирования решено, что объект находится в совместном владении, то в общем случае не известно, когда и кем он будет удалён. Может вызывающий код не хочет, чтоб какая-то левая функция удалила объект без его ведома? Поэтому и передаёт другим в пользование shared_ptr. Чтобы выразить факт того, что функция DoSomething гарантировано удалит объект (или возьмёт время его жизни в своё единоличное управление), то в своей сигнатуре она должна использовать unique_ptr. И вызывающий код туда ничего кроме unique_ptr передать не сможет. Он должен передать владение объектом в функцию с помощью move-семантики.
Записан

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

Сообщений: 579


Просмотр профиля
« Ответ #35 : Февраль 08, 2017, 15:30 »

shared/raw, unique/raw
Никогда не оправдано. Только вернули raw - полностью потеряли контроль над объектом.

Под контролем здесь скорее всего подразумевается управление временем жизни экземпляра объекта. То есть простой механизм сбора мусора?

Ассоциативные связи агрегации (shared/composite) обеспечивают управление временем жизни экземпляра, а вот другие виды ассоциативных связей совершенно не обязаны это делать. Как задать ассоциативную связь отличную от агрегации для unique_ptr, кроме как raw? Обычная ссылка не подойдет, так как во-первых ссылка и указатель сущности разной природы, а во-вторых ссылка не может быть изменена в дальнейшем. Для shared в критических местах тоже лишний раз счетчик трогать нежелательно. Если есть алгоритмическая гарантия того, что экземпляр не удалится во время выполнения (например, заранее заведен guard), то вполне резонно использовать и raw указатель.

Другое дело не рекомендовать использовать сочетания shared/raw, а рекомендовать shared/weak, где это возможно. A shared/raw оставить для продвинутого использования, с учетом того что имеется понимание опасности того, что это за собой влечет.

Для того чтобы совсем отказаться от raw указателей не хватает еще достаточного количества сущностей в стандарте.

shared/my_any
Это вообще как?

Это может быть реализовано как угодно). Можно и свой огород налепить, например, логировать операции с указателем, считать какую-нибудь статистику и т.п., был бы прикладной смысл. Кстати, под shaed не обязательно только shared_ptr понимать.  Смеющийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #36 : Февраль 08, 2017, 15:52 »

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

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

Сразу хочу отметить, я говорю про указатели отдаваемые наружу. Внутри некоего класса иногда можно использовать raw-указатели, но отдавать его наружу очень опасно (а c shared_ptr так вообще).

Для того чтобы совсем отказаться от raw указателей не хватает еще достаточного количества сущностей в стандарте.
Пишите свои. Используйте ссылки. Отказаться от raw-указателей можно было уже много лет назад. Улыбающийся

Это может быть реализовано как угодно). Можно и свой огород налепить, например, логировать операции с указателем, считать какую-нибудь статистику и т.п., был бы прикладной смысл. Кстати, под shaed не обязательно только shared_ptr понимать.  Смеющийся
Ааа. А то у меня my_any ассоциировалось с boost::any. И я испугался. Улыбающийся
« Последнее редактирование: Февраль 08, 2017, 16:03 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #37 : Февраль 08, 2017, 16:05 »

Может вызывающий код не хочет, чтоб какая-то левая функция удалила объект без его ведома? Поэтому и передаёт другим в пользование shared_ptr. Чтобы выразить факт того, что функция DoSomething гарантировано удалит объект (или возьмёт время его жизни в своё единоличное управление), то в своей сигнатуре она должна использовать unique_ptr. И вызывающий код туда ничего кроме unique_ptr передать не сможет. Он должен передать владение объектом в функцию с помощью move-семантики.
Пример
Код
C++ (Qt)
void DoSomething( SomeData * data )
{
 ...
 delete data;
}
 
Это и так грубая ошибка/просмотр, оставляющая вызывающего с невалидным указателем. Если есть необходимость мочить указатель в ф-ции (достаточно редкий случай), то просто и хорошо
Код
C++ (Qt)
void DoSomething( SomeData *& data )
{
 ...
 delete data;
 data = new ...
// data = 0;
}
 

И это достаточно веские резоны. Если на этапе проектирования решено, что объект находится в совместном владении,
Хорошо, допустим решено, но сколько данных реально шарится? Да %20 отсилы, как бы не меньше
 
то в общем случае не известно, когда и кем он будет удалён.
В подавляющем большинстве случаев - прекрасно известно. Напр
Код
C++ (Qt)
// вызывающий
DoSomething(theSharedData.get());
 
Не вижу здесь ничего плохого. Написал в ф-ции delete - ну сам "злобный Буратино", в конце-концов мог и в самой ф-ции сделать get и delete. Время жизни - для ф-ции forever. Так от каких мифических угроз защищаемся? А вот утяжеление кода и, особенно, затруднение отладки - минусы очень ощутимые.

Для того чтобы совсем отказаться от raw указателей не хватает еще достаточного количества сущностей в стандарте.
Да, shared_ptr гораздо чаще лепится для "сборки мусора" (другого-то ничего нет), а не потому что действительно шарится
« Последнее редактирование: Февраль 08, 2017, 16:08 от Igors » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #38 : Февраль 08, 2017, 16:38 »

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

Об этом я как раз и писал раннее, что вместо указателей необходимо использовать различные виды умных ссылок (wrapper), простейшим из которых является std::reference_wrapper. Указатель в явном виде никогда не говорит о том какую конкретно ассоциацию он реализует (кроме unique возможно). Ссылка - это представитель объекта, псевдоним, для использующей стороны она выглядит как сам объект, указатель не выглядит как объект.

Обычная ссылка - это Type & или const Type &, она не может быть изменена в дальнейшем.


Сразу хочу отметить, я говорю про указатели отдаваемые наружу. Внутри некоего класса иногда можно использовать raw-указатели, но отдавать его наружу очень опасно (а c shared_ptr так вообще).

Для того чтобы совсем отказаться от raw указателей не хватает еще достаточного количества сущностей в стандарте.
Пишите свои. Используйте ссылки. Отказаться от raw-указателей можно было уже много лет назад. Улыбающийся

Вот свои и пишем  Смеющийся, и получаем очередной зоопарк решений. А при стыковке нескольких решений, да если еще и Qt приляпать, в ход идут добрые, старые и знакомые raw указатели. Так что не так-то просто от них совсем отказаться. Подмигивающий
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #39 : Февраль 08, 2017, 17:47 »

В подавляющем большинстве случаев - прекрасно известно. Напр
Код
C++ (Qt)
// вызывающий
DoSomething(theSharedData.get());
 
Не вижу здесь ничего плохого. Написал в ф-ции delete - ну сам "злобный Буратино", в конце-концов мог и в самой ф-ции сделать get и delete. Время жизни - для ф-ции forever.

Неизвестно.

В С++ имея хоть какой-нибудь доступ к объекту можно его убить. Элементарно:
Код
C++ (Qt)
void DoSomething( SomeClass & some_object )
{
   delete &some_object;
}
 

Никто и не пикнет. А кто вздумает const'ом защищаться, того const_cast'ом обезоружить Смеющийся. Но за такое надо по голове очень сильно бить. И это другая история.

Так от каких мифических угроз защищаемся? А вот утяжеление кода и, особенно, затруднение отладки - минусы очень ощутимые.

Защищаемся от разыменования nullptr и обращения к убитым объектам. Управляем временем жизни объекта. И в сигнатуре функции, в типах входящих и возвращаемых параметрах, яснее сообщается, что можно делать с объектом, а что нельзя.

И не надо использовать методы умных указателей, которые возвращают raw-указатели. Лучше вообще считать, что их нет( get() и им подобные). Нужны они в особых случаях и для сопряжения с legacy-кодом.
Записан

Пока сам не сделаешь...
Страниц: 1 2 [3]   Вверх
  Печать  
 
Перейти в:  


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