Зверніть увагу, що RAII є ідіомою програмування, тоді як GC - це техніка управління пам'яттю. Отже, ми порівнюємо яблука з апельсинами.
Але ми можемо обмежити RAII його аспекти управління пам'яттю тільки і порівняйте це з методами ГХ.
Основна відмінність між так званими методами управління пам’яттю на основі RAII (що насправді означає підрахунок посилань , принаймні, коли ви враховуєте ресурси пам'яті та ігноруєте інші, такі як файли) та справжніми методами збору сміття є обробка кругових посилань (для циклічних графіків ) .
При підрахунку посилань вам потрібно кодувати спеціально для них (використовуючи слабкі посилання чи інші матеріали).
У багатьох корисних випадках (згадайте std::vector<std::map<std::string,int>>
) підрахунок посилань є неявним (оскільки він може бути лише 0 або 1) і практично опускається, але функції конструктора та деструктора (суттєві для RAII) поводяться так, ніби є біт підрахунку посилань (який практично відсутня). В std::shared_ptr
є справжній лічильник посилань. Але пам'ять все ще імпліцитно управляється вручну (з new
і delete
запускається всередині конструкторів і деструкторів), але ця "неявна"delete
(у деструкторах) створює ілюзію автоматичного управління пам'яттю. Однак дзвінки new
та delete
все одно трапляються (і вони коштують часу).
До речі, GC реалізація може (і часто робить) рукоятка округлість яким - то особливим чином, але залишити це навантаження на GC (наприклад , прочитати про алгоритмі Чейні ).
Деякі алгоритми GC (зокрема, генератор копіювання смітника поколінь) не турбуються вивільненням пам'яті для окремих об'єктів, це масове вивільнення після копіювання. На практиці Ocaml GC (або SBCL) може бути швидшим, ніж справжній стиль програмування C ++ RAII (для деяких , а не для всіх типів алгоритмів).
Деякі ГК забезпечують доопрацювання (здебільшого використовується для управління зовнішніми ресурсами, не пов'язаними з пам'яттю, такими як файли), але ви будете використовувати їх рідко (оскільки більшість значень споживають лише ресурси пам'яті). Недоліком є те, що доопрацювання не дає жодної гарантії термінів. Практично кажучи, програма, яка використовує доопрацювання, використовує її як крайній засіб (наприклад, закриття файлів все одно має відбуватися більш-менш явно поза доопрацюванням, а також з ними).
Ви все ще можете мати витоки пам’яті з GC (а також з RAII, принаймні при неправильному використанні), наприклад, коли значення зберігається в якійсь змінній або якомусь полі, але ніколи не буде використано в майбутньому. Вони просто трапляються рідше.
Рекомендую прочитати довідник зі збору сміття .
У коді C ++, ви можете використовувати GC Boehm в або MPS Ravenbrook в або код самостійно трасування збирач сміття . Звичайно, використання ГК - це компроміс (є певні незручності, наприклад, невизначеність, відсутність гарантій термінів тощо).
Я не думаю, що RAII є найкращим способом роботи з пам’яттю у всіх випадках. У декількох випадках кодування вашої програми в справді та ефективно реалізованих GC (згадайте Ocaml або SBCL) може бути простішим (розроблятись) та швидшим (виконувати), ніж кодувати його у вишуканому стилі RAII на C ++ 17. В інших випадках це не так. YMMV.
Як приклад, якщо ви кодуєте інтерпретатор схеми в C ++ 17 із наймодернішим стилем RAII, вам все одно доведеться кодувати (або використовувати) явний GC всередині нього (оскільки купа схеми має циркулярність). І більшість перевірених помічників кодуються мовами, заснованими на GC, часто функціональними (єдиний, який я знаю, який кодується на C ++ - це Lean ) з поважних причин.
До речі, я зацікавлений знайти таку реалізацію схеми C ++ 17 (але менш зацікавлений у її кодуванні), бажано з деякими багатопотоковими можливостями.