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

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

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

Сообщений: 3260


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

И что, получив такую ссылку я должен все время следить не скопирована ли она?


Эм, компилятор выдаст ошибку при попытке скопировать, на то он и юник.

А что (какой ф-ционал) хотелось получить? И что здесь понимается под уникальностью? Только один владеет? (unique_ptr). Тогда зачем помещать его в контейнер - ведь это подразумевает обращение к этому контейнеру.

Код:
class Node
{
public:
    Node *child(int index) { return _children.at(index).get(); }

private:
    std::vector<std::unique_ptr<Node>> _children;
};
« Последнее редактирование: Февраль 03, 2017, 15:02 от Авварон » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Код:
class Node
{
public:
    Node *child(int index) { return _children.at(index).get(); }

private:
    std::vector<std::unique_ptr<Node>> _children;
};
Смешивать "голых с умными" совсем нехорошо. Но даже если и так - какую же выгоду мы поимели с unique_ptr? Вообще часто замечал что вумные указатели лепятся без каких-либо оснований, типа "это круто/грамотно"  Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


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

Смешивать "голых с умными" совсем нехорошо. Но даже если и так - какую же выгоду мы поимели с unique_ptr? Вообще часто замечал что вумные указатели лепятся без каких-либо оснований, типа "это круто/грамотно"  Улыбающийся

1) Не надо писать руками qDeleteAll().
2) Exception-safety.
Код:
_children.push_back(new Node); // oooops!
« Последнее редактирование: Февраль 03, 2017, 15:59 от Авварон » Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



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

Ведь мне необходимо в некоторых методах возвращать указатель на объект, так пусть он и будет завёрнут в shared_ptr.

Это плохая идея - возвращать голый указатель на объект под управлением умного указателя. Нужно стараться обходиться unique_ptr, shared_ptr, weak_ptr и ссылками на объект.
Согласен. Я только в начале пути освоения этих шаблонов и проект местами пока что требует голые указатели Улыбающийся
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



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

Код:
class Node
{
public:
    Node *child(int index) { return _children.at(index).get(); }

private:
    std::vector<std::unique_ptr<Node>> _children;
};
Смешивать "голых с умными" совсем нехорошо.
Критикуешь - предлагай. Как вернуть указатель на потомка?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


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

Критикуешь - предлагай. Как вернуть указатель на потомка?

Ну в данном примере можно и ссылку. Или указатель.
Вообще, то что там под "капотом" юник волновать никого не должно - либо мы, когда получаем указатель, имеем овнершип (и должны удалять), либо не имеем.
Ссылка явно говорит о том, что не имеем. Возврат шаред/юник - наоборот. Возврат голого указателя заставляет читать документацию (привет, Qt).
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



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

Встречал рекомендацию детей хранить как weak, а их родителей как shared.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


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

Критикуешь - предлагай. Как вернуть указатель на потомка?

А не нужно с указателями работать, нужно с ссылками - обычные или std::reference_wrapper, а указатели глубокоо внутри держать.
Со ссылкой так вольно уже не позабавишься), придется как минимум преобразовывать.

А вообще, умные указатели unique_ptr и shared_ptr в простейшем виде реализуют понятие агрегации - обобщенной и композитной. Но с ними должны быть связаны и ассоциации, которые не реализуют агрегацию в принципе. Такого рода ассоциации могут быть реализованы разными способами.

Если повсеместно в явном виде в API используются unique_ptr и shared_ptr, то естественно тогда и голые указатели использовать (для shared реализован еще и безопасный weak). Но будьте готовы, что сам экземпляр объекта можно будет "украсть" (std::move в помощь).

Поэтому лучше всего умные указатели скрывать где-то внутри, а для доступа к данным и реализаций ассоциаций использовать всякого рода ссылки.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #23 : Февраль 03, 2017, 18:18 »

Если упростить, то должна быть возможность владеть объектом, и ссылаться на него (в определённый момент времени получить доступ к объекту, не владея им). unique_ptr и shared_ptr владеют объектом, а weak_ptr ссылается на него. Для unique_ptr нет "ссылающегося" умного указателя (аналога weak), остаются только голый указатель и ссылка, что совсем не умно и не безопасно. Так что в текущих std реалиях для организации владения и связей объектов безопасно можно использовать связку shared_ptr/weak_ptr.

При использовании shared_ptr голый указатель можно заменить на weak_ptr. Какой алгоритм работы с голым указателем?
Код
C++ (Qt)
void SomeClass::someMethod( SomeObject * object_ptr )
{
   if ( object_ptr != nullptr )
   {
       SomeObject & object = *object_ptr;
       object.doSomething();
   }
}
 

Причём проверка ( object_ptr != nullptr ) не даёт особых гарантий. Объект может быть удалён, а указатель будет продолжать указывать на мусор. С использованием weak_ptr алгоритм аналогичный:
Код
C++ (Qt)
void SomeClass::someMethod( weak_ptr< SomeObject > object_weak )
{
   shared_ptr< SomeObject > object_guard = object_weak.lock();
   if ( object_guard )
   {
       SomeObject & object = *object_guard;
       object.doSomething();
   }
}
 

В этом случае гарантий больше. Во-первых, можно проверить, что объект существует на момент обращения к нему. Во-вторых, время жизни объекта продлевается на время обращения к нему (на время существования object_guard). Даже если все  внешние shared_ptr< SomeObject > удалятся, метод SomeClass::someMethod сможет нормально завершить работу с переданным объектом.
Записан

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

Сообщений: 11445


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

Код
C++ (Qt)
void SomeClass::someMethod( weak_ptr< SomeObject > object_weak )
...
 

В этом случае гарантий больше. Во-первых, можно проверить, что объект существует на момент обращения к нему. Во-вторых, время жизни объекта продлевается на время обращения к нему (на время существования object_guard). Даже если все  внешние shared_ptr< SomeObject > удалятся, метод SomeClass::someMethod сможет нормально завершить работу с переданным объектом.
Если это просто аргумент метода/ф-ции, то нет особой разницы что предавать (хоть голый) т.к. никто не собирается ни владеть ни удалять - попользовался в методе и все. Реально проблема возникает когда "не владеет (и не создает) но хранит и пользуется". Связка shared + weak неплоха но всех проблем не решает, напр
Код
C++ (Qt)
void SomeClass::someMethod( void )
{
   shared_ptr< SomeObject > guard = m_object_weak.lock(); // член m_object_weak
   if  (guard)
   {
     ...
   }
   else {
    // И здесь что ???
   }
}
Не всегда во второй ветке можно ничего не делать. А объявлять m_object_shared (вместо m_object_weak) - свои минусы, выходит как бы "2 владельца", изменив одного надо перезарядить и второго

Update: и вообще стоит ли (упорно) добиваться чтобы абсолютно все указатели были так или иначе вумными? Мое мнение - нет, не стоит, лучше пусть небольшая часть. Но если уж вумный - не должно быть таких голых
« Последнее редактирование: Февраль 04, 2017, 09:45 от Igors » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



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

Update: и вообще стоит ли (упорно) добиваться чтобы абсолютно все указатели были так или иначе вумными? Мое мнение - нет, не стоит, лучше пусть небольшая часть. Но если уж вумный - не должно быть таких голых
Конечно стоит. Именно все указатели должны быть умными, в 21 веке то. А если используешь умные указатели, то о голых нужно полностью забыть (или извращения в коде неизбежны).
К сожалению legacy Qt не позволяет это сделать, но к радости программирование не ограничивается только Qt.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



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

Цитировать
Language is called c++ and not ++c because the language is improved but many people use it as C.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


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

Код
C++ (Qt)
struct SomeClass {
 ...
 shared_ptr<SomeData> m_data;
 ...
};
Вроде бы все норм. Теперь не надо инициализировать m_data в конструкторе и удалять в деструкторе. И он может быть нулевым, поэтому умный указатель, а не просто член SomeData. Но вот неясно, действительно ли мы собирались его шарить? Увидев такое объявление - надо ли иметь ввиду что неск SomeClass юзают один m_data? Или это так просто, "умный указатель лучше"?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



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

Увидев такое объявление - надо ли иметь ввиду что неск SomeClass юзают один m_data? Или это так просто, "умный указатель лучше"?
А для такого объявления ваши вопросы уже не актуальны? Улыбающийся

Код
C++ (Qt)
struct SomeClass {
 ...
 SomeData *m_data;
 ...
};

А если еще такое, то без документации (просмотра исходников) не понять, а что это за указатель и кто должен удалять данные по этому указателю.
Код
C++ (Qt)
struct SomeClass {
 ...
 SomeData *data() const;
 ...
};
« Последнее редактирование: Февраль 05, 2017, 13:37 от Old » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


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

Если упростить, то должна быть возможность владеть объектом, и ссылаться на него (в определённый момент времени получить доступ к объекту, не владея им). unique_ptr и shared_ptr владеют объектом, а weak_ptr ссылается на него. Для unique_ptr нет "ссылающегося" умного указателя (аналога weak), остаются только голый указатель и ссылка, что совсем не умно и не безопасно. Так что в текущих std реалиях для организации владения и связей объектов безопасно можно использовать связку shared_ptr/weak_ptr.

Если говорить строго, то владение, ссылание - это все отношения ассоциаций, а shared_ptr/weak_ptr, unique_ptr и любой my_ptr - все это инструменты управления временем жизни экземпляра объекта с определенными свойствами, с помощью которых уже могут быть реализованы любые ассоциативные связи.

В зависимости от конкретного случая вполне оправдано использование инструментов в любом сочетании shared/weak, shared/raw, unique/raw (raw - "голый" указатель), shared/my_any, так как все они имеют разную стоимость своего использования. Нужна потокобезопасность - считайте ссылки shared/weak, нужна скорость - используйте unique/raw и т.д., валидность указателей обеспечивайте другим способом (логикой использования).

Не обязательно shared/weak инструментарий должен реализовывать только обобщенное владение, на этой основе вполне логично реализуется и уникальное владение, и неявно обобщенное. В этом же ключе - нет никакого смысла реализовывать weak для unique, так как реализация такого unique должна повторить shared (на случай продления времени жизни экземпляру с помощью guard в примере).

Для практического применения на первый план выходит реализация конкретной ассоциативной связи, а способ ее внутренней реализации может (и должен) быть скрыт глубоко внутри. Ассоциативная связь подразумевает некоторое представление самого экземпляра объекта, в простейшем случае псевдонима (ссылки). И указатели во всем их разнообразии все же не являются представлением экземпляра, таким представлением являются разнообразные умные ссылки - представители объекта с разными свойствами.

К сожалению механизм умных ссылок вообще почти не продуман в стандарте, появилась только простейшая реализация в виде std::reference_wrapper, но сам принцип их построения понятен - использование паттерна Adapter (Wrapper). В соседней теме про корову есть наброски пары реализаций ImplicitWrapper. Улыбающийся

В любом случае, соблазн использовать raw указатели всегда очень велик, особенно на начальном этапе при непродуманной архитектуре - потом выясним ху из ху.  Веселый Использование внятных абстракций типа wrapper, существенно повышают качество кода и понятность модели, но требуют наличия взаимодействия достаточно большого количества сущностей реализующих - ассоциации, продление времени жизни, доступ на чтение, доступ на запись и др.  Подмигивающий
Записан
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


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