Как я вижу, умные указатели широко используются во многих реальных проектах C ++.
Хотя некоторые интеллектуальные указатели, очевидно, полезны для поддержки RAII и передачи прав собственности, также существует тенденция использования общих указателей по умолчанию в качестве способа «сборки мусора» , так что программисту не нужно слишком много думать о распределении ,
Почему общие указатели более популярны, чем интеграция надлежащего сборщика мусора, такого как Boehm GC ? (Или вы согласны с тем, что они более популярны, чем реальные GC?)
Я знаю о двух преимуществах обычных GC перед подсчетом ссылок:
- Обычные алгоритмы GC не имеют проблем с референтными циклами .
- Подсчет ссылок, как правило, медленнее, чем правильный сборщик мусора.
Каковы причины использования интеллектуальных указателей для подсчета ссылок?
c++
garbage-collection
Миклош Гомоля
источник
источник
std::unique_ptr
достаточно, и поэтому он имеет нулевые накладные расходы по сравнению с необработанными указателями с точки зрения производительности во время выполнения. Используяstd::shared_ptr
везде, вы также затеняли бы семантику владения, потеряв одно из основных преимуществ интеллектуальных указателей, помимо автоматического управления ресурсами - четкое понимание цели, стоящей за кодом.Ответы:
Некоторые преимущества подсчета ссылок перед сборкой мусора:
Низкие накладные расходы. Сборщики мусора могут быть довольно навязчивыми (например, заставлять вашу программу зависать в непредсказуемое время, пока происходит цикл сбора мусора) и достаточно интенсивно использовать память (например, объем памяти вашего процесса излишне возрастает до многих мегабайт, прежде чем сборка мусора, наконец, включится)
Более предсказуемое поведение. С подсчетом ссылок вы гарантированно освободите свой объект, как только исчезнет последняя ссылка на него. С другой стороны, при сборке мусора ваш объект будет освобожден «когда-нибудь», когда система обойдет его. Для оперативной памяти это обычно не является большой проблемой на настольных компьютерах или слегка загруженных серверах, но для других ресурсов (например, файловых дескрипторов) вам часто нужно их закрывать как можно скорее, чтобы избежать потенциальных конфликтов в дальнейшем.
Simpler. Подсчет ссылок может быть объяснен за несколько минут и реализован за час или два. Сборщики мусора, особенно с достойной производительностью, чрезвычайно сложны, и не многие понимают их.
Стандарт. C ++ включает подсчет ссылок (через shared_ptr) и друзей в STL, что означает, что большинство программистов на C ++ знакомы с ним, и большая часть кода C ++ будет работать с ним. Однако никакого стандартного сборщика мусора в C ++ не существует, а это означает, что вы должны выбрать один и надеяться, что он хорошо подойдет для вашего случая использования - и если это не так, то это ваша проблема, а не язык.
Что касается предполагаемых недостатков подсчета ссылок - не обнаружение циклов является проблемой, но я никогда не сталкивался лично за последние десять лет с использованием подсчета ссылок. Большинство структур данных естественно ациклические, и если вы сталкиваетесь с ситуацией, когда вам нужны циклические ссылки (например, родительский указатель в узле дерева), вы можете просто использовать слабый_ptr или необработанный указатель C для «обратного направления». Пока вы знаете о потенциальной проблеме при проектировании структур данных, это не проблема.
Что касается производительности, у меня никогда не было проблем с производительностью подсчета ссылок. У меня были проблемы с производительностью сборки мусора, в частности случайные зависания, которые может вызвать GC, для которых единственное решение («не размещать объекты») можно было бы перефразировать как «не использовать GC» ,
источник
make_shared
возвращаетесь. Тем не менее, задержка имеет тенденцию быть большей проблемой в приложениях реального времени, но пропускная способность, как правило, более важна, поэтому отслеживание GC так широко используется. Я не буду так быстро говорить о них плохо.Чтобы получить хорошую производительность от GC, GC должен иметь возможность перемещать объекты в памяти. В таком языке, как C ++, где вы можете напрямую взаимодействовать с областями памяти, это практически невозможно. (Microsoft C ++ / CLR не считается, поскольку вводит новый синтаксис для указателей, управляемых GC, и, таким образом, фактически является другим языком.)
Boehm GC, хотя и является изящной идеей, на самом деле является худшим из обоих миров: вам нужен malloc (), который работает медленнее, чем хороший GC, и поэтому вы теряете детерминированное поведение распределения / освобождения без соответствующего повышения производительности поколения GC. , Кроме того, он по необходимости консервативный, поэтому он не обязательно соберет весь ваш мусор в любом случае.
Хороший, хорошо настроенный GC может быть отличной вещью. Но в таком языке, как C ++, выгоды минимальны, а затраты зачастую просто не стоят того.
Тем не менее, будет интересно посмотреть, как C ++ 11 становится все более популярным, начинают ли лямбды и семантики захвата вести сообщество C ++ к тем же типам проблем выделения ресурсов и времени жизни объектов, которые заставили сообщество Lisp изобретать GC в первом место.
Смотрите также мой ответ на связанный вопрос на StackOverflow .
источник
Правда, но объективно, подавляющее большинство кода теперь написано на современных языках с отслеживанием сборщиков мусора.
Это плохая идея, потому что вам все еще нужно беспокоиться о циклах.
Ух ты, у тебя так много неправильного мышления:
ГК Бёма не является «правильным» ГК в любом смысле этого слова. Это действительно ужасно. Это консервативно, поэтому оно протекает и неэффективно по конструкции. Смотрите: http://flyingfrogblog.blogspot.co.uk/search/label/boehm
Совместно используемые указатели объективно не так популярны, как GC, поскольку подавляющее большинство разработчиков используют языки GC и не нуждаются в общих указателях. Просто посмотрите на Java и Javascript на рынке труда по сравнению с C ++.
Вы, кажется, ограничиваете рассмотрение C ++, потому что, я полагаю, вы думаете, что GC - это тангенциальная проблема. Это не так ( единственный способ получить достойный сборщик мусора - это с самого начала разработать язык и виртуальную машину для него), поэтому вы вводите предвзятость выбора. Люди, которые действительно хотят правильной сборки мусора, не придерживаются C ++.
Вы ограничены C ++, но хотели бы иметь автоматическое управление памятью.
источник
В MacOS X и iOS, а также у разработчиков, использующих Objective-C или Swift, подсчет ссылок популярен, потому что он обрабатывается автоматически, а использование сбора мусора значительно сократилось, поскольку Apple больше не поддерживает его (мне сказали, что приложения, использующие сборка мусора прекратится в следующей версии MacOS X, а сборка мусора никогда не была реализована в iOS). Я действительно серьезно сомневаюсь, что когда-либо было доступно много программного обеспечения, использующего сборку мусора.
Причина избавления от сборки мусора: она никогда не работала надежно в среде в стиле C, где указатели могли «убегать» в области, недоступные сборщику мусора. Apple твердо верит и считает, что подсчет ссылок происходит быстрее. (Здесь можно сделать какие-либо заявления об относительной скорости, но никто не смог убедить Apple). И, в конце концов, никто не использовал сборку мусора.
Первое, что изучает любой разработчик MacOS X или iOS, - это как справляться с циклами ссылок, так что это не проблема для реального разработчика.
источник
Самый большой недостаток сборки мусора в C ++ заключается в том, что получить правду невозможно:
В C ++ указатели не живут в своем собственном сообществе, они смешаны с другими данными. Таким образом, вы не можете отличить указатель от других данных, которые просто имеют битовый шаблон, который можно интерпретировать как действительный указатель.
Следствие: любой сборщик мусора в C ++ будет пропускать объекты, которые должны быть собраны.
В C ++ вы можете делать арифметику указателей для получения указателей. Таким образом, если вы не найдете указатель на начало блока, это не означает, что на этот блок нельзя ссылаться.
Следствие. Любой сборщик мусора в C ++ должен принимать во внимание эти корректировки, рассматривая любую битовую последовательность, которая может указывать в любом месте блока, в том числе сразу после его конца, как действительный указатель, который ссылается на блок.
Примечание. Никакой сборщик мусора в C ++ не может обрабатывать код с помощью таких хитростей:
Правда, это вызывает неопределенное поведение. Но некоторый существующий код более умен, чем полезен, и он может инициировать предварительное освобождение сборщиком мусора.
источник