Использовал указанную конструкцию для наполнения вектора на объектами по их чисто виртуальному предку (аналог abstract class в жаве). Коллега утверждает, что это выстрел в ногу и надо всегда использовать vector<shared_ptr<T>>.
Кто прав?
Мой довод: на компьютере программиста всё работает (C) c unique_ptr, в то время как shared_ptr это оверхед с int-м на куче, который не даёт видимых (сейчас) преимуществ.
Довод коллеги: мнение основано на личном опыте поддержки и фиксения кода.
Здравствуйте, Mr Bombastic, Вы писали:
MB>Использовал указанную конструкцию для наполнения вектора на объектами по их чисто виртуальному предку (аналог abstract class в жаве). Коллега утверждает, что это выстрел в ногу и надо всегда использовать vector<shared_ptr<T>>. MB>Кто прав?
Он не прав, shared_ptr это крайняя мера и требуется редко. Если у тебя нет никакого разделяемого владения (например два владеющих хэндлера, и неизвестно кто из них раньше отработает), то и shared_ptr не нужен.
Возможно твой коллега спутал std::unique_ptr с древним std::auto_ptr, который к тому же уже deprecated.
MB>Мой довод: на компьютере программиста всё работает (C) c unique_ptr, в то время как shared_ptr это оверхед с int-м на куче
Там ещё и deleter хранится, ещё и thread-safe(атомарные) передёргивания счётчика (но, справедливости ради, если тебе было достаточно movable unique_ptr, то и передёргиваний быть не должно, ибо при перемещениях нет нужды дёргать счётчик), а если ещё и создавать не через std::make_shared то и вовсе лишняя аллокация.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Там ещё и deleter хранится, ещё и thread-safe(атомарные) передёргивания счётчика (но, справедливости ради, если тебе было достаточно movable unique_ptr, то и передёргиваний быть не должно, ибо при перемещениях нет нужды дёргать счётчик), а если ещё и создавать не через std::make_shared то и вовсе лишняя аллокация.
Слона-то я и не заметил (атомарный счётчик) — это значит memory barrier по counter и по deleter должен быть.
Здравствуйте, Mr Bombastic, Вы писали:
MB>Кто прав?
оба не годятся, но твой коллега прав, т.к. из двух не обладающих value-семантикой смартпоинтеров shared_ptr вызовет меньше всего проблем, т.к. он copy-constructable и упрошает работу с удалением полиморфными объектов за счёт хранения deleter'а.
Здравствуйте, antropolog, Вы писали:
A>оба не годятся, но твой коллега прав, т.к. из двух не обладающих value-семантикой смартпоинтеров shared_ptr вызовет меньше всего проблем, т.к. он copy-constructable и упрошает работу с удалением полиморфными объектов за счёт хранения deleter'а.
Первое утверждение я не распарсил, к чему вообще? Второе- ну а какая проблема вызвать delete у полиморфного обьекта? Смысл же что о полиморфном объекте ничего не известно кроме базового типа.
Здравствуйте, antropolog, Вы писали:
A>оба не годятся, но твой коллега прав, т.к. из двух не обладающих value-семантикой смартпоинтеров shared_ptr вызовет меньше всего проблем, т.к. он copy-constructable
Если в коде есть какие-то закладывания на value-семантику в этом случае (неверные, ибо ни то ни другое не является value) — то copy-constructable может только усугубить ситуацию, а никак не улучшить.
A>и упрошает работу с удалением полиморфными объектов за счёт хранения deleter'а.
У ТС с этим не должно быть никаких проблем, ибо по всей видимости в базовом классе у него публичный виртуальный деструктор
MB>Кто прав?
Для начала надо разобраться нужен ли там пойнтер вообще. Ссылка на Жаву пугает. Если нужен — то конечно unique_ptr. Shared ptr судя по условию задачи не нужен.
Здравствуйте, Vamp, Вы писали:
MB>>Кто прав? V>Для начала надо разобраться нужен ли там пойнтер вообще. Ссылка на Жаву пугает. Если нужен — то конечно unique_ptr. Shared ptr судя по условию задачи не нужен.
Нужно изобразить иерархию с базовым типом для демонстрации некоего паттерна проектирования. Коллекция элементов базового типа, по ней перебор. Жаву не надо бояться, она не кусается- каждому овощу своё место на грядке.
UPD Обсудили с коллегой дальше, после моих размышлений насчёт deleter-а и внешнего аллокатора. Сошлись, что use-case для shared_ptr такой:
динамическая библиотека (API) возвращает какой-то объект (factory method), завёрнутый в shared_ptr. Этот первый shared_ptr захватывает delete-р с аллокатором, который выделил память под этот объект. Дальше через копирующий конструктор, счётчик и delete-р копируются в shared_ptr вызывающего кода. И дальше уже без вариантов, можно хранить только в коллекции из shared_ptr.
Здравствуйте, Mr Bombastic, Вы писали:
MB>UPD Обсудили с коллегой дальше, после моих размышлений насчёт deleter-а и внешнего аллокатора. Сошлись, что use-case для shared_ptr такой: MB>динамическая библиотека (API) возвращает какой-то объект (factory method), завёрнутый в shared_ptr. Этот первый shared_ptr захватывает delete-р с аллокатором, который выделил память под этот объект. Дальше через копирующий конструктор, счётчик и delete-р копируются в shared_ptr вызывающего кода. И дальше уже без вариантов, можно хранить только в коллекции из shared_ptr.
Т.е. резюмируя, нужна в использовании shared_ptr диктуется не тем, как объекты используются, а тем, как они создаются в вашем конкретном приложении, так ?