Почему у C ++ нет сборщика мусора?

Я не задаю этот вопрос из-за достоинств сборщика мусора в первую очередь. Моя основная причина в том, чтобы спросить об этом, что я знаю, что Бьярне Страуструп сказал, что C ++ будет иметь сборщик мусора в определенный момент времени.

С учетом сказанного, почему он не был добавлен? На C ++ уже есть сборщики мусора. Это только одна из тех вещей, которые проще сказать, чем сделать? Или есть другие причины, по которым он не был добавлен (и не будет добавлен в C ++ 11)?

Перекрестные ссылки:

  • Сборщики мусора для C ++

Чтобы уточнить, я понимаю причины, по которым у C ++ не было сборщика мусора, когда оно было впервые создано. Мне интересно, почему сборщик не может быть добавлен.

    Может быть добавлена ​​неявная assembly мусора, но она просто не сделала разреза. Вероятно, из-за не только осложнений внедрения, но и из-за того, что люди не могут прийти к общему консенсусу достаточно быстро.

    Цитата самого Бьярна Страустрапа:

    Я надеялся, что сборщик мусора, который может быть включен по желанию, будет частью C ++ 0x, но было достаточно технических проблем, которые я должен выполнить только с подробной спецификацией того, как такой сборщик интегрируется с остальной частью языка , если предоставлено. Как и в случае с всеми функциями C ++ 0x, существует экспериментальная реализация.

    Здесь есть хорошее обсуждение темы.

    Общий обзор:

    C ++ очень мощный и позволяет делать практически все. По этой причине он автоматически не накладывает на вас много вещей, которые могут повлиять на производительность. Сбор мусора может быть легко реализован с помощью интеллектуальных указателей (объектов, которые обводят указатели ссылочным числом, которые автоматически удаляются, когда счетчик ссылок достигает 0).

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

    Есть 2 типа сбора мусора …

    Явная assembly мусора:

    C ++ 0x будет иметь garbage collection через указатели, созданные с помощью shared_ptr

    Если вы хотите, вы можете использовать его, если вы этого не хотите, вы не будете вынуждены его использовать.

    В настоящее время вы можете использовать boost: shared_ptr, если вы не хотите ждать C ++ 0x.

    Неявная assembly мусора:

    Тем не менее, у него нет прозрачной коллекции мусора. Тем не менее, это будет фокус для будущих спецификаций C ++.

    Почему у Tr1 нет неявной сборки мусора?

    Есть много вещей, которые должны были иметь tr1 из C ++ 0x, Бьярне Страуструп в предыдущих интервью заявил, что tr1 не имеет столько, сколько ему бы хотелось.

    Чтобы добавить к обсуждению здесь.

    Известны проблемы с сборкой мусора, и понимание их помогает понять, почему в C ++ нет ни одного.

    1. Производительность?

    Первая жалоба часто касается производительности, но большинство людей не понимают, о чем они говорят. Как проиллюстрировано Martin Beckett проблема может быть не самой производительной, а предсказуемой.

    В настоящее время широко используются 2 семейства ГЦ:

    • Mark-And-Sweep kind
    • Тип счета-подсчета

    Mark And Sweep быстрее (меньше влияет на общую производительность), но он страдает от синдрома «замораживания мира»: т.е. когда GC запускается, все остальное прекращается до тех пор, пока GC не очистится. Если вы хотите построить сервер, который отвечает за несколько миллисекунд … некоторые транзакции не оправдают ваших ожиданий 🙂

    Проблема Reference Counting отличается: подсчет ссылок добавляет накладные расходы, особенно в многопоточных средах, потому что вам нужно иметь атомный счет. Кроме того, существует проблема эталонных циклов, поэтому вам нужен умный алгоритм для обнаружения этих циклов и устранения их (как правило, «замораживание мира» тоже, хотя и менее частый). В общем, на сегодняшний день такой вид (хотя обычно более отзывчивый или, скорее, замораживание реже) медленнее, чем Mark And Sweep .

    Я видел документ от разработчиков Eiffel, которые пытались реализовать сборщик Reference Counting Garbage Collector, который имел бы аналогичную глобальную производительность Mark And Sweep без аспекта «Замораживание мира». Для GC требовалось отдельную нить. Алгоритм был немного пугающим (в конце), но в документе была хорошая работа по введению понятий по одному и показ эволюции алгоритма от «простой» версии до полноценной. Рекомендуемое чтение, если только я могу вернуть руки в файл PDF …

    2. Приобретение ресурсов – это инициализация

    Это распространенная идиома на C++ что вы будете обернуть владение ресурсами внутри объекта, чтобы обеспечить их надлежащее освобождение. В основном он используется для памяти, поскольку у нас нет сборки мусора, но он также полезен, тем не менее, для многих других ситуаций:

    • блокировки (multithreading, дескриптор файла, …)
    • подключений (к базе данных, другому серверу, …)

    Идея состоит в том, чтобы правильно контролировать время жизни объекта:

    • он должен быть жив, если вам это нужно
    • его следует убить, когда вы закончите с ним

    Проблема GC заключается в том, что если это помогает с первым и в конечном итоге гарантирует, что позже … этого «конечного» может быть недостаточно. Если вы отпустите блокировку, вам действительно понравится, что она будет выпущена сейчас, чтобы она не блокировала дальнейшие звонки!

    Языки с GC имеют две работы:

    • не используйте GC при достаточном распределении стека: обычно это относится к проблемам производительности, но в нашем случае это действительно помогает, поскольку область определяет продолжительность жизни
    • using конструкцию … но это явный (слабый) RAII, тогда как в C ++ RAII неявна, так что пользователь НЕ МОЖЕТ НЕ НЕВОЗМОЖНО сделать ошибку (опустив ключевое слово using )

    3. Умные указатели

    Умные указатели часто отображаются как серебряная пуля для обработки памяти на C++ . Часто я слышал: нам не нужен GC, потому что у нас есть умные указатели.

    Нельзя ошибиться.

    Умные указатели помогают: auto_ptr и unique_ptr используют концепции RAII, чрезвычайно полезны. Они настолько просты, что вы можете писать их самим довольно легко.

    Когда нужно обмениваться собственностью, тем не менее это становится сложнее: вы можете делиться между несколькими streamами, и есть несколько тонких проблем с обработкой счета. Поэтому, естественно, идет к shared_ptr .

    Это здорово, это то, что Boost для всех, но это не серебряная пуля. На самом деле основная проблема с shared_ptr заключается в том, что она эмулирует GC, реализованный посредством Reference Counting но вам нужно реализовать цикл обнаружения все самостоятельно … Urg

    Конечно, это weak_ptr , но я, к сожалению, уже видел утечки памяти, несмотря на использование shared_ptr из-за этих циклов … и когда вы находитесь в среде Multi Threaded, это очень сложно обнаружить!

    4. Каково решение?

    Серебряной пули нет, но, как всегда, это определенно возможно. В отсутствие GC необходимо четко понимать право собственности:

    • предпочитают иметь одного владельца за один раз, если возможно
    • если нет, убедитесь, что диаграмма classа не имеет никакого цикла, связанного с владением, и разбивает их с помощью тонкого приложения weak_ptr

    Так что было бы здорово иметь GC … однако это не тривиальная проблема. И в то же время нам просто нужно свернуть armва.

    Какой тип? следует ли оптимизировать его для встроенных controllerов стиральных машин, сотовых телефонов, рабочих станций или суперкомпьютеров?
    Должна ли она определять приоритетность реакции пользователя или загрузку сервера?
    следует ли использовать много памяти или много CPU?

    C / c ++ используется в слишком многих разных обстоятельствах. Я подозреваю, что что-то вроде форсированных интеллектуальных указателей будет достаточно для большинства пользователей

    Редактировать. Автоматические сборщики мусора – это не столько проблема производительности (вы всегда можете купить больше серверов), это вопрос предикативной производительности.
    Не зная, когда GC собирается пинать, это похоже на использование нарколептического пилота авиакомпании, большую часть времени они замечательные, но когда вам действительно нужна отзывчивость!

    Одна из главных причин, по которой C ++ не имеет встроенной сборки мусора, заключается в том, что garbage collection для игры с деструкторами действительно очень тяжелый. Насколько я знаю, никто не знает, как его полностью решить. Есть много проблем, с которыми приходится иметь дело:

    • детерминированные времена жизни объектов (подсчет ссылок дает вам это, но GC не делает. Хотя это может и не быть большой сделкой).
    • что произойдет, если деструктор выбрасывает, когда объект собирает мусор? Большинство языков игнорируют это исключение, поскольку на самом деле нет блока catch для его переноса, но это, вероятно, не приемлемое решение для C ++.
    • Как включить / отключить его? Естественно, это, скорее всего, решение для компиляции, но код, написанный для кода GC против кода, который написан для NOT GC, будет совсем другим и, вероятно, несовместимым. Как вы это примирите?

    Это лишь некоторые из проблем.

    Хотя это старый вопрос, есть еще одна проблема, что я не вижу никого, кто обращался вообще: garbage collection почти невозможно указать.

    В частности, стандарт C ++ достаточно осторожен, чтобы указать язык в терминах внешне наблюдаемого поведения, а не как реализация достигает такого поведения. Однако в случае сбора мусора практически не наблюдается внешне наблюдаемого поведения.

    Общая идея сборки мусора заключается в том, что она должна сделать разумную попытку убедить, что распределение памяти будет успешным. К сожалению, практически невозможно гарантировать, что распределение памяти будет успешным, даже если у вас есть сборщик мусора. Это в какой-то мере верно, но особенно в случае C ++, потому что (возможно) невозможно использовать копировальный коллектор (или что-то подобное), который перемещает объекты в памяти во время цикла сбора.

    Если вы не можете перемещать объекты, вы не можете создать единое непрерывное пространство памяти, из которого будут выполняться ваши ассигнования, и это означает, что ваша куча (или бесплатный магазин или что вы предпочитаете его называть) может и, вероятно, будет , становятся fragmentированными с течением времени. Это, в свою очередь, может препятствовать успеху выделения, даже если на нем больше свободного места, чем запрашиваемая сумма.

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

    Тем не менее, это сильнее, чем было предложено для C ++. Предыдущее предложение [предупреждение: PDF] (которое упало) ничего не гарантировало. На 28 страницах предложения, что вы получили на пути внешне наблюдаемого поведения, была единственная (ненормативная) заметка, в которой говорилось:

    [Примечание: для программ, собранных для мусора, высококачественная хостинговая реализация должна пытаться максимизировать количество недостижимой памяти, которую она исправляет. -End note]

    По крайней мере, для меня это вызывает серьезный вопрос о возврате инвестиций. Мы собираемся сломать существующий код (никто точно не знает, сколько, но определенно совсем немного), ставят новые требования к реализациям и новые ограничения на код, и то, что мы получаем взамен, вполне возможно, совсем ничего?

    Даже в лучшем случае то, что мы получаем, это программы, которые на основе тестирования с Java , вероятно, потребуют примерно в шесть раз больше памяти для работы с той же скоростью, что и сейчас. Хуже того, assembly мусора была частью Java с самого начала – C ++ добавляет к сборщику мусора все больше ограничений, что почти наверняка будет иметь еще худшее соотношение затрат и выгод (даже если мы выйдем за frameworks гарантированного предложения и предположим, что это будет некоторые выгоды).

    Я обобщаю ситуацию математически: это сложная ситуация. Как знает любой математик, комплексное число имеет две части: реальную и мнимую. Мне кажется, что то, что мы имеем здесь, – это реальные издержки, но выгоды, которые (по крайней мере, в основном) являются мнимыми.

    Если вы хотите автоматическую сборку мусора, для C ++ есть хорошие коммерческие сборщики мусора и public domain. Для приложений, в которых garbage collection подходит, C ++ – превосходный compilation мусора, который отличается выгодным соотношением с другими языками, собранными с мусором. См. Язык программирования C ++ (3-е издание) для обсуждения автоматической сборки мусора на C ++. См. Также, Ханс-Дж. Сайт Boehm для сбора мусора C и C ++. Кроме того, C ++ поддерживает методы программирования, которые позволяют управлять памятью безопасно и неявно без сборщика мусора.

    Источник: http://www.stroustrup.com/bs_faq.html#garbage-collection

    Что касается того, почему у него нет встроенного устройства, если я правильно помню, это было изобретено до того, как GC был тем, и я не верю, что язык мог иметь GC по нескольким причинам (IE Backward compatibilty with C)

    Надеюсь это поможет.

    Stroustrup сделал несколько хороших комментариев по этому поводу на конференции Going Native 2013 года.

    Просто пропустите примерно 25m50s в этом видео . (Я бы порекомендовал смотреть все видео на самом деле, но это пропускает материал о сборке мусора.)

    Когда у вас действительно отличный язык, который упрощает (и безопасен, и предсказуем, и легко читается, и легко учит) напрямую обращаться с объектами и ценностями, избегая (явного) использования куча, тогда вы даже не хотите garbage collection.

    С современным C ++ и материалом, который у нас есть на C ++ 11, garbage collection больше не желателен, за исключением ограниченных обстоятельств. На самом деле, даже если хороший сборщик мусора встроен в один из основных компиляторов C ++, я думаю, что он не будет использоваться очень часто. Будет легче , а не сложнее избежать GC.

    Он показывает этот пример:

     void f(int n, int x) { Gadget *p = new Gadget{n}; if(x<100) throw SomeException{}; if(x<200) return; delete p; } 

    Это небезопасно в C ++. Но это также небезопасно в Java! В C ++, если функция возвращается раньше, delete никогда не будет вызываться. Но если у вас была полная assembly мусора, например, на Java, вы просто получаете предложение о том, что объект будет разрушен «в какой-то момент в будущем» ( обновление: это еще хуже, чем это. Java не обещает вызывать финализатор когда-либо - его, возможно, никогда не назовут). Это недостаточно хорошо, если Gadget содержит дескриптор открытого файла или соединение с базой данных или данные, которые вы буферизировали для записи в базу данных в более поздней точке. Мы хотим, чтобы Гаджет был уничтожен, как только он закончил, чтобы освободить эти ресурсы как можно скорее. Вы не хотите, чтобы ваш сервер базы данных боролся с тысячами подключений к базе данных, которые больше не нужны - он не знает, что ваша программа завершена.

    Так в чем же решение? Есть несколько подходов. Очевидный подход, который вы будете использовать для подавляющего большинства ваших объектов:

     void f(int n, int x) { Gadget p = {n}; // Just leave it on the stack (where it belongs!) if(x<100) throw SomeException{}; if(x<200) return; } 

    Это занимает меньше символов для ввода. У него нет new препятствий. Вам не нужно дважды вводить Gadget . Объект уничтожается в конце функции. Если это то, что вы хотите, это очень интуитивно. Gadget ведет себя так же, как int или double . Предсказуемый, легко читаемый, простой в обучении. Все это «ценность». Иногда большая ценность, но ценности легче учить, потому что у вас нет этого «действия на расстоянии», которое вы получаете с указателями (или ссылками).

    Большинство объектов, которые вы делаете, предназначены для использования только в функции, которая их создала, и, возможно, передаются в качестве входных данных для дочерних функций. Программисту не нужно думать о «управлении памятью» при возврате объектов или обмениваться другими объектами через широко разделенные части программного обеспечения.

    Масштабы и срок службы важны. В большинстве случаев проще, если срок службы совпадает с объемом. Это легче понять и легче учить. Если вам требуется другое время жизни, должно быть очевидно, что вы читаете код, который вы делаете, используя shared_ptr например. (Или возвращать (большие) объекты по значению, используя перемещение-семантику или unique_ptr .

    Это может показаться проблемой эффективности. Что делать, если я хочу вернуть гаджет из foo() ? Семантика перемещения C ++ 11 облегчает возврат больших объектов. Просто напишите Gadget foo() { ... } и он будет просто работать и работать быстро. Вам не нужно возиться с && самостоятельно, просто возвращайте вещи по значению, и язык часто сможет выполнить необходимую оптимизацию. (Еще до C ++ 03 компиляторы отлично справились с задачей избежать ненужного копирования).

    Как сказал Страуступ в другом месте видео (перефразируя): «Только компьютерный ученый будет настаивать на копировании объекта, а затем уничтожить оригинал (смеется аудитория). Почему бы просто не переместить объект прямо в новое место? Это то, что люди (а не компьютерные ученые).

    Когда вы можете гарантировать, что требуется только одна копия объекта, гораздо проще понять время жизни объекта. Вы можете выбрать, какую страtagsю жизни вы хотите, и garbage collection там, если хотите. Но когда вы понимаете преимущества других подходов, вы обнаружите, что garbage collection находится в нижней части списка ваших предпочтений.

    Если это не сработает для вас, вы можете использовать unique_ptr , или если это не так, shared_ptr . Хорошо написанный C ++ 11 короче, легче читается и проще в обучении, чем многие другие языки, когда дело доходит до управления памятью.

    Идея, лежащая в основе C ++, заключалась в том, что вы не платите за производительность, которую не используете. Таким образом, добавление сборки мусора означало бы, что некоторые программы запускаются прямо на оборудовании так, как это делает C, а некоторые – в какой-то виртуальной машине времени исполнения.

    Ничто не мешает вам использовать какую-либо форму интеллектуальных указателей, привязанных к некоторому механизму сбора мусора третьей стороны. Кажется, я помню, как Microsoft делала что-то подобное с COM, и это не помогло.

    Чтобы ответить на большинство «почему» вопросов о C ++, прочитайте « Дизайн и эволюция C ++»

    Одним из основополагающих принципов исходного языка C является то, что память состоит из последовательности байтов, а код должен заботиться только о том, что означают эти байты в тот момент, когда они используются. Modern C позволяет компиляторам налагать дополнительные ограничения, но C включает в себя – и C ++ сохраняет – способность разложить указатель на последовательность байтов, собрать любую последовательность байтов, содержащих одни и те же значения, в указатель, а затем использовать этот указатель для доступ к более раннему объекту.

    Хотя эта способность может быть полезной или даже незаменимой – в некоторых видах приложений язык, который включает в себя эту способность, будет очень ограничен в его способности поддерживать любую полезную и надежную сборку мусора. Если компилятор не знает всего, что было сделано с битами, составляющими указатель, он не сможет узнать, может ли существовать информация, достаточная для восстановления указателя, где-то в юниверсе. Поскольку можно было бы сохранить эту информацию таким образом, чтобы компьютер не смог получить доступ, даже если бы знал о них (например, байты, составляющие указатель, могли быть показаны на экране достаточно долго, чтобы кто-то мог писать их на листе бумаги), компьютеру может быть невозможно понять, можно ли использовать указатель в будущем.

    Интересным причудом многих фреймов, собранных с помощью мусора, является то, что ссылка на объект не определена содержащимися в нем шаблонами бит, а зависимость между битами, содержащимися в ссылке на объект, и другой информацией, хранящейся в другом месте. В C и C ++, если бит-шаблон, хранящийся в указателе, идентифицирует объект, этот бит-шаблон идентифицирует этот объект до тех пор, пока объект не будет явно уничтожен. В типичной системе GC объект может быть представлен битовой диаграммой 0x1234ABCD в один момент времени, но следующий цикл GC может заменить все ссылки на 0x1234ABCD ссылками на 0x4321BABE, после чего объект будет представлен последним шаблоном. Даже если нужно было отобразить битовый шаблон, связанный с ссылкой на объект, а затем позже его прочитать с клавиатуры, не ожидается, что один и тот же бит-шаблон будет использоваться для идентификации того же объекта (или любого объекта).

    Because these days, C++ doesn’t need it anymore.

    The situation, for code written these days (C++17 and following the official language Coding Guidelines ) is as follows:

    • Most memory ownership-related code is in libraries (especially those providing containers).
    • Most use of code involving memory ownership follows the RAII pattern , so allocation is made on construction and deallocation on destruction, which happens when exiting the scope in which something was allocated.
    • You do not explicitly allocate or deallocate memory directly .
    • Raw pointers do not own memory (if you’ve followed the guidelines), so you can’t leak by passing them around.
    • If you’re wondering how you’re going to pass the starting addresses of sequences of values in memory – you’ll be doing that with a span ; no raw pointer needed.
    • If you really need an owning “pointer”, you use C++’ standard-library smart pointers – they can’t leak, and are quite efficient. Alternatively, you can pass ownership across scope boundaries with “owner pointers” . These are uncommon and must be used explicitly; and they allow for partial static checking against leaks.

    “Oh yeah? But what about…

    … if I just write code the way we’ve written C++ so far?”

    Indeed, you could just disregard all of the guidelines and write leaky application code – and it will compile and run (and leak), same as always.

    But it’s not a “just don’t do that” situation, where the developer is expected to be virtuous and exercise a lot of self control; it’s just not simpler to write non-conforming code, nor is it faster to write, nor is it better-performing. Gradually it will also become more difficult to write, as you would face an increasing “impedance mismatch” with what conforming code provides and expects.

    … if I reintrepret_cast ? Or do pointer arithmetic? Or other such hacks?”

    Indeed, if you put your mind to it, you can write code that messes things up despite playing nice with the guidelines. Но:

    1. You would do this rarely (in terms of places in the code, not necessarily in terms of fraction of execution time)
    2. You would only do this intentionally, not accidentally
    3. Doing so will stand out in a codebase conforming to the guidelines
    4. It’s the kind of code in which you would bypass the GC in another language anyway

    … library development?”

    If you’re a C++ library developer then you do write unsafe code involving raw pointers, and you are required to code carefully and responsibly – but these are self-contained pieces of code written by experts.

    so, bottom line: There’s really no motivation to collect garbage generally, as you all but make sure not to produce garbage. GC is on the way to becoming a non-problem with C++.

    That is not to say GC isn’t an interesting problem for certain specific applications, when you want to employ custom allocation and de-allocations strategies. For those you would want custom allocation and de-allocation, not a language-level GC.

    All the technical talking is overcomplicating the concept.

    If you put GC into C++ for all the memory automatically then consider something like a web browser. The web browser must load a full web document AND run web scripts. You can store web script variables in the document tree. In a BIG document in a browser with lots of tabs open, it means that every time the GC must do a full collection it must also scan all the document elements.

    On most computers this means that PAGE FAULTS will occur. So the main reason, to answer the question is that PAGE FAULTS will occur. You will know this as when your PC starts making lots of disk access. This is because the GC must touch lots of memory in order to prove invalid pointers. When you have a bona fide application using lots of memory, having to scan all objects every collection is havoc because of the PAGE FAULTS. A page fault is when virtual memory needs to get read back into RAM from disk.

    So the correct solution is to divide an application into the parts that need GC and the parts that do not. In the case of the web browser example above, if the document tree was allocated with malloc, but the javascript ran with GC, then every time the GC kicks in it only scans a small portion of memory and all PAGED OUT elements of the memory for the document tree does not need to get paged back in.

    To further understand this problem, look up on virtual memory and how it is implemented in computers. It is all about the fact that 2GB is available to the program when there is not really that much RAM. On modern computers with 2GB RAM for a 32BIt system it is not such a problem provided only one program is running.

    As an additional example, consider a full collection that must trace all objects. First you must scan all objects reachable via roots. Second scan all the objects visible in step 1. Then scan waiting destructors. Then go to all the pages again and switch off all invisible objects. This means that many pages might get swapped out and back in multiple times.

    So my answer to bring it short is that the number of PAGE FAULTS which occur as a result of touching all the memory causes full GC for all objects in a program to be unfeasible and so the programmer must view GC as an aid for things like scripts and database work, but do normal things with manual memory management.

    And the other very important reason of course is global variables. In order for the collector to know that a global variable pointer is in the GC it would require specific keywords, and thus existing C++ code would not work.

    SHORT ANSWER: We don’t know how to do garbage collection efficiently (with minor time and space overhead) and correctly all the time (in all possible cases).

    LONG ANSWER: Just like C, C++ is a systems language; this means it is used when you are writing system code, eg, operating system. In other words, C++ is designed, just like C, with best possible performance as the main target. The language’ standard will not add any feature that might hinder the performance objective.

    This pauses the question: Why garbage collection hinders performance? The main reason is that, when it comes to implementation, we [computer scientists] do not know how to do garbage collection with minimal overhead, for all cases. Hence it’s impossible to the C++ compiler and runtime system to perform garbage collection efficiently all the time. On the other hand, a C++ programmer, should know his design/implementation and he’s the best person to decide how to best do the garbage collection.

    Last, if control (hardware, details, etc.) and performance (time, space, power, etc.) are not the main constraints, then C++ is not the write tool. Other language might serve better and offer more [hidden] runtime management, with the necessary overhead.

    When you compare C++ with Java, you can see immediately that C++ was not designed with implicit Garbage Collection in mind, while Java was.

    Having things like arbitrary pointers in C-Style and deterministic destructors does not only slow down the performance of GC-implementations, it would also destroy backward compatibility for a large amount of C++-legacy-code.

    In addition to that, C++ is a language that is intended to run as standalone executable instead of having a complex run-time environment.

    All in all: Yes it would be possible to add Garbage Collection to C++, but for the sake of continuity it is better not to do so. The cost of doing so would be greater than the benefit.

    Mainly for two reasons:

    1. Because it doesn’t need one (IMHO)
    2. Because it’s pretty much incompatible with RAII, which is the cornerstone of C++

    C++ already offers manual memory management, stack allocation, RAII, containers, automatic pointers, smart pointers… That should be enough. Garbage collectors are for lazy programmers who don’t want to spend 5 minutes thinking about who should own which objects or when should resources be freed. That’s not how we do things in C++.

    Imposing garbage collection is really a low level to high level paradigm shift.

    If you look at the way strings are handled in a language with garbage collection, you will find they ONLY allow high level string manipulation functions and do not allow binary access to the strings. Simply put, all string functions first check the pointers to see where the string is, even if you are only drawing out a byte. So if you are doing a loop that processes each byte in a string in a language with garbage collection, it must compute the base location plus offset for each iteration, because it cannot know when the string has moved. Then you have to think about heaps, stacks, threads, etc etc.

    Давайте будем гением компьютера.