Pull to refresh

Comments 23

На самом деле умные указатели достаточно легко использовать, чтобы не было циклов. Главное — придерживаться правила, что на куче сильная ссылка на указатель может быть только у одного объекта. (под кучей я имею ввиду долгоживущие объекты на куче. Если на куче выделяется память, которая гарантированно сливается при выходе из функции — то в контексте архитектуры можно рассматривать это стековой памятью, и можно хранить сильную ссылку) Все остальные ссылки на куче — должны быть слабыми. Как правило это иерархия в форме дерева (деревьев), горизонтальные связи, и связи от потомков к родителю — слабые ссылки.
Это только кажется сложным, но на этапе разработки хорошо видно какая именно связь между объектами, и лично мне никаких удобств не доставляет.
А ещё бывают алгоритмы, которые находят и освобождают циклы. Работают они примерно так: каждый раз когда счётчик умного указателя декрементируется, этот указатель добавляется в «список указателей, которые могут входить в циклы». Периодически из всех указателей в этом списке запускается поиск в глубину, который находит и удаляет циклы. Существует даже многопоточный вариант, который не требует остановки всех потоков.
Описание на английском: researcher.watson.ibm.com/researcher/files/us-bacon/Bacon03Pure.pdf
Как раз таким способом и пользуюсь. После многих граблей научился создавать сильные указатели только в момент конструкции объекта, в случаях же остальных использую слабые указатели (передача объекта другому конструктору или функции, например), т.е. там, где нарушается иерархия дерева.
Угу, только стоит помнить что слабая ссылка имеет некоторый оверхед в виде отдельного счетчика и потенциального кешмисса. Поэтому если параметр достаточно локальный (например ходит только на стеке в текущей операции) — то сильная ссылка будет все таки быстрее.
Все верно, немного простых правил и умные указатели очень хорошая вещь. Мне просто стало интересно можно ли эти правила переложить на программу, а мне, ленивому, ничего не делать.
Rust
Там собсно сделали отслеживание владения и алиасинга компилятором. От зацикленных умных указателей конечно не спасает на 100%, но ногу себе отстрелить гораздо труднее.
Да, мне тоже нравится их подход, но все никак времени нет опробовать.
Если сильная ссылка может быть только у одного объекта, который гарантирует, что его время жизни больше, чем у всех остальных пользователей указателя, то shared_ptr с подсчетом ссылок не нужен вообще. В этом случае у этого объекта хранится std::unique_ptr или его аналог, а у всех остальных обычный указатель.
Согласно C++ Core Guidelines владелец указателя помечается как owner, а все остальные являются простыми указателями, для которых нельзя применять оператор delete. Проверка последнего условия выполняется с помощью статического анализа.

shared_ptr или его аналоги нужны только в том случае, когда нет явного владельца указателя и не известно, чье время жизни будет больше.
Ну я поэтому и написал — придерживаться, а не строго следовать правилу. Понятное дело во всех правилах бывают исключения. Кроме того не стоит забывать, что у слабых ссылок (в отличие от голых указателей) огромный плюс в том, что нам не нужно будет чистить везде указатели когда объект умрет, что обеспечивает нам дополнительную безопасность, т.к. в случае случайного разыменования будет гарантированное обращение по null. Ну и кроме того shared нас обеспечивает дополнительной безопасностью, т.к. бывают случаи когда shared хранится только на стеке и передавать ссылку куда-то, меняя иерархию. В общем ссылки всякие нужны (в том числе и unique).
Почему бы не взять стандартный Hans Boehm Garbage Collector?

http://hboehm.info/gc/
У меня не было уверенности что GC мне на 100% нужен. Я даже не думал о нем, он получился когда я захотел развить идею умных указателей. Собственно все это большой эксперимент чтобы понять как оно работает и какие плюсы и минусы. Именно поэтому я не рассматривал использование готовых решений.
Я думаю здесь стоит упоминуть garbage collection которую сделали/делают в blink (движке chrome): www.chromium.org/blink/blink-gc

Как я понимаю в основном это решение проблемы того, что C++ объекты отображаются в язык со сборкой мусора — javascript и поэтому хорошо бы этому сборщику мусора помочь со стороный C++.
Вы не пробовали использовать другие стратегии сборки мусора?
Мне кажется, необязательно останавливать весь мир каждый кадр — с помощью подсчёта ссылок можно удалять большинство объектов. Для оставшихся циклических использовать алгоритмы типа инкрементальной сборки мусора, которые позволяют делать сборку за несколько вызовов. (хотя, наверно, тогда уж проще взять язык со встроенным сборщиком мусора и не писать велосипеды)
Нет, к сожалению не пробовал. Именно как раз потому что
тогда уж проще взять язык со встроенным сборщиком мусора и не писать велосипеды
Я бы добавил «Этап 0» (он же «Этап 7»): как можно чаще использовать RAII (т.е. автоматическое выделение памяти) вместо динамического выделения.

Хотя полностью избавиться от динамического выделения удается редко, однако к этому следует стремиться, т.к. RAII по сути — это compile-time «garbage collector», простой, надежный, быстрый и масштабируемый.

Этапом 0 должен быть анализ требований и подбор технологий под них. Если понадобился GC в C++, то проблема скорее всего в выборе технологий (C++) или персонале (который плохо знает C++).

Полностью поддерживаю. Вопрос в использовании подхода на сложных динамических сценариях, но и здесь есть решения. Откровенно говоря, за всё время ещё ни разу не встречал в С++ необходимости использовать мусоросборщик в масштабах программы (исключая специализированные классы, внутри которых та или иная сборка «мусора» может быть уместна).
Мне кажется, что в комментариях к статье будет вполне адекватно упомянуть и о подходе, который позволяет избегать проблем с памятью без мусоросборщика. Не претендуя на «метод на все случаи жизни», очень надеюсь, он будет полезен некоторым. Речь идёт об этой хабрастатье.
Я бы немного переписал статью.
Начал бы так же: «Ручное управление памятью в С++...».
А всё, что идёт дальше, я бы выбросил и написал «не используется».
В теги запишем «RAII, деструктор, умный указатель».
Будет гораздо интереснее и познавательнее.

И не надо придумывать про огромное количество циклов в графе зависимостей объектов. Подобные ситуации — следствие излишней увлечённостью ООП и неправильного проектирования (либо полное его отсутствие).

Если уж пишешь на плюсах, то пиши на плюсах, а не на сях, явах или каких-то других языках.

Также рекомендую почитать статью «Пять популярных мифов о языке C++» и поискать в интернете информацию по ключевым словам «GSL» и «owner<T*>».
Возможно, вы немного не поняли статью. Она не о том, что «давайте все станем ленивыми и будем использовать воот такууую фигню». Она как раз о
Если уж пишешь на плюсах, то пиши на плюсах, а не на сях, явах или каких-то других языках.


В проекте GC был сделан не столько для реального использования, сколько для того чтобы попробовать каков он в деле, и узнать возможно ли его частичное применение в проекте. Сейчас его нет в проекте, и причины этого описаны в конце статьи.
копеечка про игровые движки: в unreal engine плюсы как раз с gc идут.
UFO just landed and posted this here
Sign up to leave a comment.

Articles