Я не задаю этот вопрос из-за достоинств сборки мусора в первую очередь. Моя главная причина, по которой я спрашиваю об этом, состоит в том, что я знаю, что Бьярн Страуструп сказал, что C ++ будет иметь сборщик мусора в определенный момент времени.
С учетом сказанного, почему он не был добавлен? Уже есть несколько сборщиков мусора для C ++. Это просто одна из тех вещей, которые легче сказать, чем сделать? Или есть другие причины, по которым он не был добавлен (и не будет добавлен в C ++ 11)?
Перекрестные ссылки:
Просто чтобы прояснить, я понимаю причины, по которым в C ++ не было сборщика мусора при его создании. Мне интересно, почему коллекционер не может быть добавлен в.
c++
garbage-collection
c++11
Джейсон Бейкер
источник
источник
Ответы:
Неявная сборка мусора могла быть добавлена, но это не помогло. Вероятно, не только из-за сложностей в реализации, но и из-за того, что люди не могут прийти к общему согласию достаточно быстро.
Цитата самого Бьярна Страуструпа:
Существует хорошее обсуждение этой темы здесь .
Общий обзор:
C ++ очень мощный и позволяет вам делать практически все что угодно. По этой причине он не навязывает вам автоматически много вещей, которые могут повлиять на производительность. Сборка мусора может быть легко реализована с помощью интеллектуальных указателей (объектов, которые обертывают указатели счетчиком ссылок, которые автоматически удаляются, когда счетчик ссылок достигает 0).
C ++ был создан с учетом конкурентов, у которых не было сборки мусора. Эффективность была главной заботой, с которой C ++ должен был противостоять критике по сравнению с C и другими.
Есть 2 типа сборки мусора ...
Явная сборка мусора:
C ++ 0x будет иметь сборку мусора через указатели, созданные с помощью shared_ptr
Если вы хотите, вы можете использовать его, если вы не хотите, вы не обязаны использовать его.
В настоящее время вы можете использовать boost: shared_ptr, если вы не хотите ждать C ++ 0x.
Неявная сборка мусора:
У этого нет прозрачной сборки мусора все же. Это будет основной темой для будущих спецификаций C ++.
Почему Tr1 не имеет неявной сборки мусора?
Бьярн Страуструп (Bjarne Stroustrup) в предыдущих интервью сказал, что есть много вещей, которые должен был иметь tr1 в C ++ 0x.
источник
smart_ptr's
? Как бы вы сделали низкоуровневую разметку в стиле Unix, с мешающим сборщиком мусора? Другие вещи будут затронуты, такие как многопоточность. Python имеет глобальную блокировку интерпретатора в основном из-за его сборки мусора (см. Cython). Держите это подальше от C / C ++, спасибо.std::shared_ptr
) - это циклические ссылки, которые вызывают утечку памяти. Поэтому вы должны осторожно использоватьstd::weak_ptr
для прерывания циклов, что является грязным. Марка и развертка в стиле GC не имеют этой проблемы. Нет никакой внутренней несовместимости между многопоточностью / разветвлением и сборкой мусора. Java и C # имеют высокопроизводительную вытесняющую многопоточность и сборщик мусора. Существуют проблемы, связанные с приложениями реального времени и сборщиком мусора, поскольку большинству сборщиков мусора приходится мешать миру работать.std::shared_ptr
) - циклические ссылки» и ужасная производительность, которая иронична, потому что повышение производительности обычно оправдывает использование C ++ ... flyingfrogblog.blogspot.co.uk/2011/01/…Чтобы добавить к дискуссии здесь.
Существуют известные проблемы со сборкой мусора, и их понимание помогает понять, почему в C ++ их нет.
1. Производительность?
Первая жалоба часто касается производительности, но большинство людей не понимают, о чем говорят. Как показывает
Martin Beckett
проблема, может быть не производительность как таковая, а предсказуемость производительности.В настоящее время широко распространены 2 семейства GC:
Это
Mark And Sweep
быстрее (меньше влияет на общую производительность), но страдает от синдрома «заморозить мир»: то есть, когда включается GC, все остальное останавливается, пока GC не выполнит очистку. Если вы хотите построить сервер, который отвечает за несколько миллисекунд ... некоторые транзакции не будут соответствовать вашим ожиданиям :)Проблема в
Reference Counting
другом: подсчет ссылок увеличивает издержки, особенно в многопоточных средах, потому что вам нужен атомный счет. Кроме того, существует проблема референтных циклов, поэтому вам нужен умный алгоритм для обнаружения этих циклов и их устранения (обычно реализуется также «заморозить мир», хотя и реже). В целом, на сегодняшний день этот тип (хотя обычно более отзывчивый или, скорее, замерзает реже) медленнее, чемMark And Sweep
.Я видел статью разработчиков Eiffel, которые пытались реализовать
Reference Counting
сборщик мусора, который имел бы аналогичную глобальную производительностьMark And Sweep
без аспекта «Freeze The World». Требуется отдельная тема для GC (типовая). Алгоритм был немного пугающим (в конце), но статья хорошо поработала, представляя концепции по одному и показывая эволюцию алгоритма от «простой» версии к полноценной. Рекомендуем прочитать, если только я смогу вернуть руки к PDF-файлу ...2. Приобретение ресурсов - это инициализация (RAII)
Это распространенная идиома, заключающаяся в
C++
том, что вы будете связывать владение ресурсами внутри объекта, чтобы обеспечить их правильное освобождение. Он в основном используется для памяти, поскольку у нас нет сборки мусора, но, тем не менее, он полезен и для многих других ситуаций:Идея состоит в том, чтобы должным образом контролировать время жизни объекта:
Проблема GC состоит в том, что, если он помогает с первым и в конечном итоге гарантирует, что позже ... этого "предельного" может быть недостаточно. Если вы снимаете блокировку, вам бы очень хотелось, чтобы она была снята сейчас, чтобы она не блокировала дальнейшие вызовы!
У языков с GC есть два обходных пути:
using
построить ... но это явный (слабый) RAII, в то время как в C ++ RAII является неявным, так что пользователь НЕ МОЖЕТ невольно сделать ошибку (опускаяusing
ключевое слово)3. Умные указатели
Умные указатели часто выглядят как серебряная пуля для обработки памяти
C++
. Часто я слышал: нам не нужен GC, потому что у нас есть умные указатели.Нельзя быть более неправильным.
Умные указатели действительно помогают:
auto_ptr
иunique_ptr
используют концепции RAII, что чрезвычайно полезно. Они настолько просты, что вы можете написать их самостоятельно довольно легко.Однако, когда нужно разделить владение, это становится более сложным: вы можете делиться между несколькими потоками, и есть несколько тонких проблем с обработкой счетчика. Поэтому человек естественно идет навстречу
shared_ptr
.Это здорово, для этого все-таки Boost, но это не серебряная пуля. На самом деле, главная проблема в
shared_ptr
том, что он эмулирует GC, реализованный с помощью,Reference Counting
но вам нужно реализовать обнаружение цикла самостоятельно ... UrgКонечно, есть такая
weak_ptr
штука, но я, к сожалению, уже видел утечки памяти, несмотря на использованиеshared_ptr
из-за этих циклов ... и когда вы находитесь в многопоточной среде, это чрезвычайно трудно обнаружить!4. Какое решение?
Серебряной пули нет, но, как всегда, это возможно. В отсутствие GC необходимо четко указать право собственности:
weak_ptr
Так что, действительно, было бы здорово иметь GC ... однако это не тривиальная проблема. А пока нам просто нужно закатать рукава.
источник
Какой тип? следует ли оптимизировать его для встроенных контроллеров стиральных машин, мобильных телефонов, рабочих станций или суперкомпьютеров?
Должно ли это расставлять приоритеты отзывчивости графического интерфейса или загрузки сервера?
он должен использовать много памяти или много процессора?
C / c ++ используется в самых разных обстоятельствах. Я подозреваю, что что-то вроде повышения умных указателей будет достаточно для большинства пользователей
Редактировать - автоматические сборщики мусора - это не столько проблема производительности (вы всегда можете купить больше серверов), это вопрос предсказуемой производительности.
Не знать, когда GC собирается вступить в бой, это все равно, что нанимать пилота-нарколептера, в большинстве случаев они великолепны, но когда вам действительно нужна отзывчивость!
источник
Одна из главных причин того, что C ++ не имеет встроенной сборки мусора, заключается в том, что заставить сборщик мусора хорошо играть с деструкторами очень сложно. Насколько я знаю, никто до сих пор не знает, как полностью это решить. Есть много вопросов для решения:
Это лишь некоторые из проблем, с которыми сталкиваются.
источник
Dispose
объекта может сделать его невозможным, но ссылки, которые указывали на объект, когда он был жив, будут продолжать делать это после его смерти. В отличие от этого, в системах без GC объекты могут быть удалены, пока существуют ссылки, и редко бывает какое-либо ограничение хаоса, который может быть нанесен, если одна из этих ссылок будет использована.Хотя это старый вопрос, есть еще одна проблема, о которой я не вижу, чтобы кто-то вообще обращался к ней: сборка мусора практически невозможно определить.
В частности, стандарт C ++ довольно осторожно определяет язык с точки зрения наблюдаемого извне поведения, а не того, как реализация достигает такого поведения. В случае сбора мусора, однако, не является практически не внешне наблюдаемое поведение.
Общая идея сбора мусора является то , что он должен сделать разумную попытку в обеспечении , что распределение памяти будет успешным. К сожалению, практически невозможно гарантировать успешное распределение памяти, даже если у вас есть сборщик мусора. В любом случае это верно в некоторой степени, но особенно в случае C ++, поскольку (вероятно) невозможно использовать копирующий сборщик (или что-либо подобное), который перемещает объекты в памяти во время цикла сбора данных.
Если вы не можете перемещать объекты, вы не можете создать единое непрерывное пространство памяти, из которого вы можете делать свои выделения - и это означает, что ваша куча (или свободное хранилище, или как вы предпочитаете называть это) может и, вероятно, будет стать фрагментированным со временем. Это, в свою очередь, может помешать успешному распределению, даже если свободной памяти больше, чем запрашиваемый объем.
Хотя может быть возможно придумать некоторую гарантию, которая гласит (по сути), что, если вы повторяете один и тот же шаблон распределения многократно, и это сработало в первый раз, оно продолжит выполняться на последующих итерациях, при условии, что выделенная память стал недоступным между итерациями. Это такая слабая гарантия, что она по сути бесполезна, но я не вижу разумной надежды на ее укрепление.
Тем не менее, это сильнее, чем было предложено для C ++. Предыдущее предложение [предупреждение: PDF] (что были понижены) не гарантия вообще ничего. На 28 страницах предложения вы заметили внешне наблюдаемое поведение в виде одной (ненормативной) записки, в которой говорилось:
По крайней мере, для меня это поднимает серьезный вопрос о возврате инвестиций. Мы собираемся сломать существующий код (никто точно не уверен, сколько, но определенно немного), наложить новые требования на реализации и новые ограничения на код, и что мы получаем взамен, вполне возможно, вообще ничего?
Даже в лучшем случае мы получаем программы, которые, основываясь на тестировании на Java , вероятно, потребуют примерно в шесть раз больше памяти для работы с той же скоростью, что и сейчас. Хуже того, сборка мусора была частью Java с самого начала - C ++ накладывает достаточно большие ограничения на сборщик мусора, чтобы он почти наверняка имел еще худшее соотношение цена / качество (даже если мы выйдем за пределы того, что предложение гарантировано, и предположим, что оно будет какая-то выгода).
Я бы суммировал ситуацию математически: это сложная ситуация. Как известно любому математику, комплексное число состоит из двух частей: действительной и мнимой. Мне кажется, что у нас есть реальные затраты, но выгоды (по крайней мере, в основном) мнимые.
источник
free
вас (я имею в видуfree
аналог языка Си). Но Java никогда не гарантирует вызова финализаторов или чего-то в этом роде. Фактически, C ++ делает гораздо больше, чем Java, для выполнения операций записи в базу данных, очистки файловых дескрипторов и так далее. Java утверждает, что имеет "GC", но разработчики Java должныclose()
все время тщательно звонить, и они должны быть очень осведомлены об управлении ресурсами, стараясь не звонитьclose()
слишком рано или слишком поздно. C ++ освобождает нас от этого. ... (продолжение)try (Whatever w=...) {...}
решайте это (и вы получите предупреждение, когда забудете). Остальные тоже проблематичны с RAII. Вызовclose()
«все время» означает, может быть, один раз на десятки тысяч строк, так что это не так уж плохо, в то время как память распределяется почти на каждую строку Java.Источник: http://www.stroustrup.com/bs_faq.html#garbage-collection
Что касается того, почему он не имеет встроенного, если я правильно помню, что он был изобретен до того, как GC был предметом , и я не верю, что язык мог иметь GC по нескольким причинам (совместимость IE с обратной связью с C)
Надеюсь это поможет.
источник
Страуструп сделал несколько хороших комментариев по этому поводу на конференции Going Native 2013 года.
Просто перейдите к 25м50 в этом видео . (Я бы порекомендовал посмотреть все видео на самом деле, но это пропускает материал о сборке мусора.)
Если у вас действительно отличный язык, который позволяет легко (и безопасно, и предсказуемо, и легко читаться, и легко учить) работать с объектами и значениями прямым способом, избегая (явного) использования куча, тогда вам даже не нужна сборка мусора.
С современным C ++ и тем, что есть в C ++ 11, сборка мусора больше не нужна, за исключением ограниченных обстоятельств. Фактически, даже если хороший сборщик мусора встроен в один из основных компиляторов C ++, я думаю, что он не будет использоваться очень часто. Будет проще , а не сложнее избежать ГК.
Он показывает этот пример:
Это небезопасно в C ++. Но это также небезопасно в Java! В C ++, если функция возвращается рано,
delete
никогда не будет вызываться. Но если у вас была полная сборка мусора, такая как в Java, вы просто получаете предположение, что объект будет уничтожен «в какой-то момент в будущем» ( Обновление: это еще хуже, чем это. Java делает НеОбещаю называть финализатор когда-либо - возможно, он никогда не будет вызван). Этого недостаточно, если гаджет содержит дескриптор открытого файла, или соединение с базой данных, или данные, которые вы буферизировали для записи в базу данных на более позднем этапе. Мы хотим, чтобы гаджет был уничтожен, как только он будет завершен, чтобы освободить эти ресурсы как можно скорее. Вы не хотите, чтобы ваш сервер баз данных боролся с тысячами соединений с базами данных, которые больше не нужны - он не знает, что ваша программа закончила работать.Так в чем же решение? Есть несколько подходов. Очевидный подход, который вы будете использовать для подавляющего большинства ваших объектов:
Для этого требуется меньше символов. Это не
new
мешает. Это не требует, чтобы вы печаталиGadget
дважды. Объект уничтожается в конце функции. Если это то, что вы хотите, это очень интуитивно понятно.Gadget
s ведут себя так же, какint
илиdouble
. Предсказуемый, легкий для чтения, легкий в обучении. Все это «ценность». Иногда это большая ценность, но ценности легче учить, потому что у вас нет такого «действия на расстоянии», которое вы получаете с помощью указателей (или ссылок).Большинство созданных вами объектов предназначены для использования только в функции, которая их создала, и, возможно, передаются в качестве входных данных для дочерних функций. Программисту не нужно думать о «управлении памятью» при возврате объектов или иным образом обмениваться объектами между различными частями программного обеспечения.
Область и срок службы важны. В большинстве случаев проще, если время жизни совпадает с областью действия. Это легче понять и легче учить. Когда вам нужно другое время жизни, должно быть очевидно, что вы читаете код, который делаете,
shared_ptr
например. (Или возвращая (большие) объекты по значению, используя семантику перемещения илиunique_ptr
.Это может показаться проблемой эффективности. Что делать, если я хочу вернуть гаджет
foo()
? Семантика перемещения C ++ 11 облегчает возвращение больших объектов. Просто напишите,Gadget foo() { ... }
и это будет просто работать, и работать быстро. Вам не нужно связываться с&&
самим собой, просто возвращайте вещи по значению, и язык часто сможет выполнить необходимые оптимизации. (Еще до C ++ 03 компиляторы проделали замечательную работу, избегая ненужного копирования.)Как сказал Страуструп в другом месте на видео (перефразируя): «Только компьютерный специалист будет настаивать на копировании объекта, а затем уничтожении оригинала. (Аудитория смеется). Почему бы просто не переместить объект непосредственно в новое место? Это то, что люди (не компьютерные ученые) ожидать. "
Когда вы можете гарантировать, что требуется только одна копия объекта, гораздо проще понять время существования объекта. Вы можете выбрать, какую политику жизни вы хотите, и уборка мусора есть, если хотите. Но когда вы поймете преимущества других подходов, вы обнаружите, что сборка мусора находится внизу вашего списка предпочтений.
Если это не работает для вас, вы можете использовать
unique_ptr
, или если это невозможно,shared_ptr
. Хорошо написанный C ++ 11 короче, его легче читать и легче изучать, чем многие другие языки, когда речь заходит об управлении памятью.источник
Gadget
не попросить что-либо еще сделать что-либо от его имени, исходный код будет совершенно безопасным в Java, если бессмысленный (для Java)delete
оператор был удален.shared_ptr<T>
специально обработать, когдаT
это «скучно». Он может решить не управлять счетчиком ссылок для этого типа, а использовать GC. Это позволило бы использовать GC без уведомления разработчика. Ashared_ptr
может просто рассматриваться как указатель GC, для подходящегоT
. Но в этом есть ограничения, и это замедлит работу многих программ.string1=string2;
будет выполнять очень быстро , независимо от длины строки (это не в буквальном смысле не более чем нагрузки регистра и регистрация магазина), и не требует какой - либо блокировки , чтобы гарантировать , что если приведенное выше утверждение выполняются в то время какstring2
IS будучи записанным,string1
будет содержать либо старое значение, либо новое значение без неопределенного поведения).shared_ptr<String>
требует много скрытой синхронизации, и назначение aString
может вести себя странно, если переменная читается и записывается одновременно. Случаи, когда хочется писать и читатьString
одновременно, не очень распространены, но могут возникнуть, если, например, какой-то код желает сделать текущие отчеты о состоянии доступными для других потоков. В .NET и Java такие вещи просто «работают».Потому что современный C ++ не нуждается в сборке мусора.
Ответ Bjarne Stroustrup на часто задаваемые вопросы по этому вопросу гласит :
Ситуация для кода, написанного в наши дни (C ++ 17 и в соответствии с официальными основными рекомендациями ), выглядит следующим образом:
"О да? Но как насчет ...
... если я просто напишу код так, как мы привыкли писать C ++ в старые времена? "
В самом деле, вы можете просто проигнорировать все рекомендации и написать неплотный код приложения - и он будет компилироваться и запускаться (и просачиваться), как всегда.
Но это не ситуация «просто не делай этого», где разработчик должен быть добродетельным и обладать большим самоконтролем; просто не проще написать несоответствующий код, и при этом это не быстрее писать, и при этом это не более эффективно. Постепенно это также станет более трудным для написания, поскольку вы столкнетесь с растущим «несоответствием импеданса» с тем, что обеспечивает и ожидает соответствующий код.
... если я
reintrepret_cast
? Или сделать сложную указательную арифметику? Или другие такие хаки?В самом деле, если вы подумаете об этом, вы можете написать код, который все испортит, несмотря на то, что вы хорошо играете с рекомендациями. Но:
... развитие библиотеки? "
Если вы разработчик библиотеки C ++, то вы пишете небезопасный код с использованием необработанных указателей, и вам необходимо кодировать аккуратно и ответственно - но это отдельные фрагменты кода, написанные экспертами (и, что более важно, проверенные экспертами).
Так вот, как сказал Бьярне: на самом деле вообще нет мотивации собирать мусор, как вы все, но старайтесь не производить мусор. GC становится не проблема с C ++.
Это не означает, что GC не является интересной проблемой для определенных конкретных приложений, когда вы хотите использовать собственные стратегии распределения и отмены распределения. Для тех, кто хотел бы иметь пользовательское распределение и удаление, а не GC уровня языка.
источник
Идея, лежащая в основе C ++, заключалась в том, что вы не заплатили бы никакого влияния на производительность функций, которые вы не используете. Таким образом, добавление сборки мусора означало бы, что некоторые программы выполняются прямо на оборудовании, как это делает C, а некоторые - в какой-то виртуальной машине времени выполнения.
Ничто не мешает вам использовать некоторые умные указатели, которые связаны с каким-то сторонним механизмом сборки мусора. Кажется, я вспоминаю, как Microsoft делала что-то подобное с COM, и это не очень хорошо.
источник
Чтобы ответить на большинство вопросов «почему» о C ++, прочитайте « Дизайн и эволюция C ++».
источник
Один из фундаментальных принципов оригинального языка Си состоит в том, что память состоит из последовательности байтов, и код должен заботиться только о том, что эти байты означают в тот момент, когда они используются. Современный C позволяет компиляторам накладывать дополнительные ограничения, но C включает - и C ++ сохраняет - возможность разложить указатель на последовательность байтов, собрать любую последовательность байтов, содержащих те же значения, в указатель, а затем использовать этот указатель для получить доступ к более раннему объекту.
Хотя эта возможность может быть полезной - или даже необходимой - в некоторых видах приложений, язык, который включает эту возможность, будет очень ограничен в своей способности поддерживать любой вид полезной и надежной сборки мусора. Если компилятор не знает всего, что было сделано с битами, составляющими указатель, он не сможет узнать, существует ли информация, достаточная для восстановления указателя, где-нибудь во вселенной. Поскольку эта информация может храниться так, чтобы компьютер не мог получить к ней доступ, даже если бы знал о них (например, байты, составляющие указатель, могли бы отображаться на экране достаточно долго, чтобы кто-то мог написать на листе бумаги), для компьютера может быть практически невозможно узнать, можно ли использовать указатель в будущем.
Интересная особенность многих сборок мусора состоит в том, что ссылка на объект определяется не битовыми шаблонами, содержащимися в нем, а отношениями между битами, содержащимися в ссылке на объект, и другой информацией, хранящейся в другом месте. В C и C ++, если битовый шаблон, хранящийся в указателе, идентифицирует объект, этот битовый шаблон будет идентифицировать этот объект, пока объект не будет явно уничтожен. В типичной системе GC объект может быть представлен битовым шаблоном 0x1234ABCD в один момент времени, но следующий цикл GC может заменить все ссылки на 0x1234ABCD ссылками на 0x4321BABE, после чего объект будет представлен последним шаблоном. Даже если нужно отобразить битовый шаблон, связанный со ссылкой на объект, а затем прочитать его обратно с клавиатуры,
источник
Все технические разговоры слишком усложняют концепцию.
Если вы автоматически включите GC в C ++ для всей памяти, тогда рассмотрите что-то вроде веб-браузера. Веб-браузер должен загрузить полный веб-документ и запустить веб-скрипты. Вы можете хранить переменные веб-скрипта в дереве документа. В БОЛЬШОМ документе в браузере с большим количеством открытых вкладок это означает, что каждый раз, когда сборщик мусора должен сделать полную коллекцию, он также должен сканировать все элементы документа.
На большинстве компьютеров это означает, что PAGE FAULTS произойдет. Таким образом, основная причина, чтобы ответить на этот вопрос, заключается в том, что ошибки страницы произойдут. Вы будете знать это, как когда ваш компьютер начнет делать много доступа к диску. Это потому, что GC должен коснуться большого количества памяти, чтобы доказать недействительные указатели. Когда у вас есть добросовестное приложение, использующее много памяти, необходимость сканировать все объекты каждой коллекции приводит к хаосу из-за ошибок страницы. Ошибка страницы - это когда виртуальная память должна быть прочитана обратно в оперативную память с диска.
Таким образом, правильное решение состоит в том, чтобы разделить приложение на части, которые нуждаются в GC, и части, которые не нуждаются. В приведенном выше примере с веб-браузером, если дерево документа было выделено с помощью malloc, но javascript работал с GC, то каждый раз, когда GC запускает его, сканируется только небольшая часть памяти и все элементы PAGED OUT памяти для дерево документов не нужно возвращать обратно.
Чтобы лучше понять эту проблему, посмотрите на виртуальную память и то, как она реализована на компьютерах. Все дело в том, что 2 ГБ доступно программе, когда на самом деле не так много оперативной памяти. На современных компьютерах с 2 ГБ ОЗУ для 32-битной системы это не такая проблема, если запущена только одна программа.
В качестве дополнительного примера рассмотрим полную коллекцию, которая должна отслеживать все объекты. Сначала вы должны проверить все объекты, доступные через корни. Затем просканируйте все объекты, видимые на шаге 1. Затем просмотрите ожидающие деструкторы. Затем снова перейдите на все страницы и отключите все невидимые объекты. Это означает, что многие страницы могут выгружаться и возвращаться в несколько раз.
Итак, мой ответ для краткости заключается в том, что количество ошибок страницы, возникающих в результате прикосновения ко всей памяти, делает невозможным полный GC для всех объектов в программе, и поэтому программист должен рассматривать GC в качестве помощи для таких вещей, как сценарии и работа с базой данных, но делать обычные вещи с ручным управлением памятью.
И другая очень важная причина, конечно, глобальные переменные. Чтобы сборщик знал, что указатель глобальной переменной находится в GC, ему потребуются определенные ключевые слова, и, следовательно, существующий код C ++ не будет работать.
источник
КОРОТКИЙ ОТВЕТ: Мы не знаем, как эффективно выполнять сборку мусора (с небольшими временными и пространственными издержками) и правильно все время (во всех возможных случаях).
ДОЛГО ОТВЕТ: Как и C, C ++ - системный язык; это означает, что он используется, когда вы пишете системный код, например, операционную систему. Другими словами, C ++, как и C, разработан с максимально возможной производительностью в качестве основной цели. Стандарт языка не добавляет никаких функций, которые могут помешать достижению цели.
Это ставит на паузу вопрос: почему сборка мусора снижает производительность? Основная причина в том, что когда речь идет о реализации, мы [компьютерные специалисты] не знаем, как выполнять сборку мусора с минимальными издержками во всех случаях. Следовательно, компилятору C ++ и системе времени выполнения невозможно постоянно выполнять сборку мусора. С другой стороны, программист C ++ должен знать свой дизайн / реализацию, и он - лучший человек, который решает, как лучше всего выполнять сборку мусора.
Наконец, если управление (оборудование, детали и т. Д.) И производительность (время, пространство, мощность и т. Д.) Не являются основными ограничениями, то C ++ не является инструментом записи. Другой язык мог бы служить лучше и предлагать больше [скрытого] управления временем выполнения с необходимыми накладными расходами.
источник
Когда мы сравниваем C ++ с Java, мы видим, что C ++ не был разработан с неявной сборкой мусора, в то время как Java была.
Наличие таких вещей, как произвольные указатели в C-Style, не только плохо для GC-реализаций, но и разрушает обратную совместимость для большого количества C ++ - устаревшего кода.
В дополнение к этому, C ++ - это язык, который предназначен для запуска в качестве автономного исполняемого файла вместо сложной среды выполнения.
В общем: да, возможно, можно добавить сборщик мусора в C ++, но ради преемственности лучше этого не делать.
источник
Главным образом по двум причинам:
C ++ уже предлагает ручное управление памятью, выделение стека, RAII, контейнеры, автоматические указатели, умные указатели ... Этого должно быть достаточно. Сборщики мусора предназначены для ленивых программистов, которые не хотят тратить 5 минут на размышления о том, кто должен владеть какими объектами и когда следует освобождать ресурсы. Это не так, как мы делаем вещи в C ++.
источник
Внедрение сбора мусора - это действительно сдвиг парадигмы от низкого уровня к высокому уровню.
Если вы посмотрите, как обрабатываются строки на языке со сборщиком мусора, вы обнаружите, что они ТОЛЬКО допускают высокоуровневые функции работы со строками и не разрешают двоичный доступ к строкам. Проще говоря, все строковые функции сначала проверяют указатели, чтобы увидеть, где находится строка, даже если вы только вытягиваете байт. Поэтому, если вы выполняете цикл, который обрабатывает каждый байт в строке на языке со сборкой мусора, он должен вычислить базовое местоположение плюс смещение для каждой итерации, потому что он не может знать, когда строка была перемещена. Тогда вы должны думать о кучах, стеках, потоках и т. Д. И т. Д.
источник