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

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

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

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

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

16 ответов


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

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

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

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

общее описание:

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

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

существует 2 типа мусора коллекция...

явная сборка мусора:

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

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

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

неявного сбора мусора:

Он не имеет прозрачной сборки мусора хотя. Это будет точкой фокусировки для будущих спецификаций C++.

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

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


чтобы добавить к дебатам здесь.

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

1. Представление ?

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

есть в настоящее время 2 семейства GC, которые широко развернуты:

  • Марк-и-развертки вида
  • подсчет ссылок вида

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

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

я видел документ Эйфелевых исполнителей, которые пытались реализовать Reference Counting сборщик мусора, который будет иметь аналогичную глобальную производительность Mark And Sweep без аспекта "заморозить мир". Это потребовало отдельного потока для GC (типичного). Алгоритм был немного пугающим (в конце), но в статье была проделана хорошая работа по введению понятий по одному и показу эволюции алгоритма от "простой" версии до полноценной один. Рекомендуется читать, если только я могу положить руки обратно на PDF-файл...

2. Приобретение Ресурсов-Это Инициализация

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

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

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

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

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

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

  • не используйте GC, когда выделение стека достаточно: обычно это для проблем производительности, но в нашем случае это действительно помогает, так как область определяет время жизни
  • using строительство... но это явный (слабый) RAII, а в C++ RAII неявный, так что пользователь не может невольно сделать ошибку (опуская using ключевое слово)

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

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

невозможно ошибиться больше.

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

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

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

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

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

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

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

действительно, было бы здорово иметь GC... однако это не тривиальная проблема. А пока нам просто нужно засучить рукава.


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

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

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


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

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

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


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

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

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

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

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

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

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

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

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

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


Если вы хотите автоматическую сборку мусора, есть хорошие коммерческие и общедоступные сборщики мусора для C++. Для приложений, где подходит сбор мусора, C++ - отличный язык сбора мусора с производительностью, которая выгодно отличается от других языков сбора мусора. Ознакомиться с язык программирования C++ (3-е издание) для обсуждения автоматическая сборка мусора в C++. См. также сайт Hans-J. Boehm для сбора мусора C и c++. Кроме того, C++ поддерживает методы программирования, которые позволяют управлению памятью быть безопасным и неявным без сборщика мусора.

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

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

надеюсь, что это помогает.


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

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

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

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

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

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

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

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

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 два раза. Объект уничтожается в конце функции. Если это то, что вы хотите, это очень интуитивно. Gadgets ведут себя так же, как int или double. Предсказуемый, легко читаемый, легко обучаемый. Все является "ценностью". Иногда большая ценность, но ценности легче преподавать, потому что у вас этого нет "действие на расстоянии", которое вы получаете с указателями (или ссылками).

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

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

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

как сказал Страуструп в другом месте видео (перефразируя):


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

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


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


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

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

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


потому что в наши дни C++ больше не нуждается в этом.

ситуация, для кода, написанного в эти дни (C++17 и после официального языка Руководство По Кодированию) следующим образом:

  • большинство кода, связанного с владением памятью, находится в библиотеках (особенно тех, которые предоставляют контейнеры).
  • большинство использовать кода, включающего владение памятью, следует за RAII шаблон, поэтому перерасчет сделан на строительство и освобождение от ответственности за уничтожение, которое происходит при выходе из области, в которой что-то было выделено.
  • вы не выделяйте и не освобождайте память напрямую.
  • сырые указатели не принадлежит (если вы следовали рекомендациям), поэтому вы не можете протекать, передавая их.
  • Если вам интересно, как вы собираетесь передавать начальные адреса последовательностей значений в памяти - вы будете делать это с помощью span; не требуется необработанный указатель.
  • Если вам действительно нужен собственный "указатель", вы используете C++' standard-библиотека интеллектуальных указателей - они не могут протекать, и довольно эффективны. Кроме того, вы можете передать право собственности через границы области с "владелец указатели". Они необычны и должны использоваться явно; и они допускают частичную статическую проверку против утечек.

"да? Но о чем?..

... если я просто напишите код так, как мы написали C++ до сих пор?"

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

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

... если я ... --0-->? Или сделать указатель арифметики? Или другие подобные хаки?"

действительно, если вы положите свой ум на это, вы можете написать код, который испортит вещи, несмотря на то, что хорошо играет с рекомендациями. Но:

  1. вы будете делать это редко (с точки зрения мест в коде, не обязательно с точки зрения доли время исполнения)
  2. вы бы сделали это намеренно, а не случайно
  3. это будет выделяться в кодовой базе, соответствующей рекомендациям
  4. это такой код, в котором вы бы обошли GC на другом языке в любом случае

... развитие библиотеки?"

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


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

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


все технические разговоры чрезмерно усложняют концепцию.

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

на большинстве компьютеры это означает, что будут возникать ошибки страницы. Поэтому основная причина, чтобы ответить на вопрос, заключается в том, что будут возникать ошибки страницы. Вы будете знать это, как когда ваш компьютер начинает делать много доступа к диску. Это связано с тем, что GC должен коснуться большого количества памяти, чтобы доказать недопустимые указатели. Когда у вас есть добросовестное приложение, использующее много памяти, сканирование всех объектов каждой коллекции вызывает хаос из-за ошибок страницы. Ошибка страницы - это когда виртуальная память должна быть прочитана обратно в ОЗУ из диск.

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

чтобы лучше понять эту проблему, посмотрите на virtual память и как она реализуется в компьютерах. Речь идет о том, что 2GB доступен для программы, когда на самом деле не так много оперативной памяти. На современных компьютерах с 2GB RAM для 32BIt-системы это не такая проблема, если работает только одна программа.

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

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

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


КОРОТКИЙ ОТВЕТ: Мы не знаем, как делать сборку мусора эффективно (с небольшими затратами времени и пространства) и правильно все время (во всех возможных случаях).

ДЛИННЫЙ ОТВЕТ: Как и C, C++ - это системный язык; это означает, что он используется при написании системного кода, например, операционной системы. Другими словами, C++ разработан так же, как C, с наилучшим возможным производительность в качестве основной цели. Стандарт языка не будет добавлять какие-либо функции, которые могут препятствуйте цели представления.

Это приостанавливает вопрос: почему сбор мусора препятствует производительности? Основная причина заключается в том, что, когда дело доходит до реализации, мы [компьютерные ученые] не знаем, как делать сборку мусора с минимальными накладными расходами для всех случаев. Следовательно, компилятор C++ и система выполнения не могут эффективно выполнять сборку мусора все время. С другой стороны, программист на C++ должен знать свой дизайн / реализацию, и он лучший человек, чтобы решить, как лучше всего сделать сборку мусора.

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


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

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

кроме того, в C++ - это язык, который предназначен для запуска исполняемого вместо сложной среды выполнения.

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


главным образом по двум причинам:

  1. потому что ему не нужен один (ИМХО)
  2. потому что это в значительной степени несовместимо с RAII, который является краеугольным камнем C++

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


навязывание сбора мусора-это действительно сдвиг парадигмы от низкого уровня до высокого уровня.

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