C ++: будет ли универсальное использование shared_ptr <> эквивалентно gc? - PullRequest
11 голосов
/ 22 октября 2011

Это просто академический вопрос (я бы никогда не сделал это в реальном коде):

Если бы я использовал shared_ptr <> повсеместно в своем коде, было бы поведение эквивалентным языку, собранному gc, как Java?

Если нет, то как поведение будет отличаться от языка, встроенного в gc? Какая конструкция C ++ даст эквивалентное поведение по сравнению со встроенным в gc языком?

Примечание. В реальном кодировании я настоятельно предпочитаю использовать RAII и строгое владение по сравнению с использованием любых умных указателей. Я также знаю, что другие менее универсальные указатели, unique_ptr <> будут более эффективными. Этот вопрос является просто вопросом эквивалентности смарт-указателя.

Ответы [ 5 ]

12 голосов
/ 22 октября 2011

Нет, будет несколько важных отличий:

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

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

Какая конструкция C ++ выдаст эквивалентное поведение по сравнению свстроенный в gc язык?

Нет.C ++ не имеет сборщика мусора, потому что нет способа реализовать правильный, надежный.(Да, я знаю GC от Boehm, и это хорошее приближение, но оно консервативно и не обнаруживает все ссылки, только те, в которых он может быть уверен на 100%. В обычной программе на C ++ нет никакой возможности, чтобы реализовать сборщик мусора, который Just Works (tm))

4 голосов
/ 22 октября 2011

@ jalf говорит об этом в своем ответе:

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

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

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

2 голосов
/ 22 октября 2011

Основным отличием является то, что подсчет ссылок сам по себе не может освободить циклические структуры данных.

Многие случаи таких структур, тем не менее, могут быть обработаны путем использования weak_ptr, а некоторые случаи могут быть обработаны путем делегирования ответственности за очистку объекту коллекции.

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

Приветствия & hth.,

2 голосов
/ 22 октября 2011

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

У вас все еще есть контроль, когда память уходит с shared_ptr.У вас нет этого с сборщиком мусора (кроме грубых команд, таких как включение / выключение или изменение его поведения).

0 голосов
/ 22 октября 2011

Стоит отметить, что общий ptr намного больше, чем ссылка на Java. Обычно это не имеет значения, но в некоторых ситуациях это может иметь значение.

В Java 6 64-битные JVM по-прежнему используют 32-битные ссылки для доступа к 32 ГБ кучи (это можно сделать, потому что объекты находятся на 8-байтовых границах). Однако общий ptr использует два указателя (каждый 8 байт в 64-битные приложения), второй указатель ссылается на объект, который содержит счетчик. В libgcc он выделяет минимум 32 байта для любого объекта malloc / new. Всего совместно используемый указатель может использовать 48 байтов, что относительно больше, чем 4 байта. 44 байта не будут иметь значения, но это может случиться, если у вас их много.

...