Beachten Sie, dass RAII eine Programmiersprache ist, während GC eine Speicherverwaltungstechnik ist. Also vergleichen wir Äpfel mit Orangen.
Aber wir können RAH auf seine Speicherverwaltung Aspekte beschränken nur und vergleichen Sie das mit GC - Techniken.
Der wesentliche Unterschied zwischen sogenannten RAII basierten Speicher - Management - Techniken (was eigentlich bedeutet Referenzzählung , zumindest wenn Sie Speicherressourcen betrachten und ignorieren die andere , die wie Dateien) und Original- Garbage - Collection - Techniken ist die Handhabung von Kreisreferenzen (für zyklische Graphen ) .
Bei der Referenzzählung müssen Sie speziell für sie codieren (unter Verwendung schwacher Referenzen oder anderer Dinge).
In vielen nützlichen Fällen (denken Sie daran std::vector<std::map<std::string,int>>
) ist die Referenzzählung implizit (da sie nur 0 oder 1 sein kann) und wird praktisch weggelassen, aber die Konstruktor- und Destruktorfunktionen (für RAII wesentlich) verhalten sich so, als ob es ein Referenzzählbit gäbe (welches fehlt praktisch). Darin std::shared_ptr
befindet sich ein echter Referenzzähler. Der Speicher wird jedoch immer noch implizit manuell verwaltet (mit new
und delete
innerhalb von Konstruktoren und Destruktoren ausgelöst), aber dieses "implizite" delete
(in Destruktoren) gibt die Illusion einer automatischen Speicherverwaltung. Anrufe an new
und delete
passieren jedoch immer noch (und sie kosten Zeit).
Übrigens kann (und tut) die GC- Implementierung die Zirkularität auf besondere Weise behandeln, aber Sie überlassen diese Belastung dem GC (z. B. lesen Sie mehr über den Cheney-Algorithmus ).
Einige GC-Algorithmen (insbesondere der Garbage Collector zum Kopieren von Generationen) machen sich nicht die Mühe, Speicher für einzelne Objekte freizugeben, sondern werden massenweise nach dem Kopieren freigegeben . In der Praxis kann der Ocaml GC (oder der SBCL GC) schneller sein als ein echter C ++ RAII-Programmierstil (für einige , nicht alle Arten von Algorithmen).
Einige GC bieten Finalisierung (meistens zum Verwalten von externen Ressourcen außerhalb des Speichers wie Dateien), aber Sie werden sie selten verwenden (da die meisten Werte nur Speicherressourcen verbrauchen). Der Nachteil ist, dass die Finalisierung keine zeitliche Garantie bietet. In der Praxis verwendet ein Programm, das die Finalisierung verwendet, diese als letzten Ausweg (z. B. sollte das Schließen von Dateien immer noch mehr oder weniger explizit außerhalb der Finalisierung und auch mit diesen erfolgen).
Mit GC (und auch mit RAII, zumindest bei unsachgemäßer Verwendung) können immer noch Speicherverluste auftreten, z. B. wenn ein Wert in einer Variablen oder einem Feld gespeichert wird, aber in Zukunft nie mehr verwendet wird. Sie kommen nur seltener vor.
Ich empfehle, das Handbuch zur Speicherbereinigung zu lesen .
In Ihrem C ++ - Code können Sie Böhms GC oder Ravenbrooks MPS verwenden oder Ihren eigenen Tracing-Garbage-Collector codieren . Natürlich ist die Verwendung eines GC ein Kompromiss (es gibt einige Unannehmlichkeiten, z. B. Nichtdeterminismus, fehlende Zeitgarantien usw.).
Ich denke nicht, dass RAII in allen Fällen die ultimative Art ist, mit dem Gedächtnis umzugehen. In mehreren Fällen kann das Codieren Ihres Programms in einer wirklich und effizienten GC-Implementierung (denken Sie an Ocaml oder SBCL) einfacher (zu entwickeln) und schneller (auszuführen) sein als das Codieren mit einem ausgefallenen RAII-Stil in C ++ 17. In anderen Fällen ist es nicht. YMMV.
Wenn Sie beispielsweise einen Scheme-Interpreter in C ++ 17 mit dem ausgefallensten RAII-Stil codieren, müssen Sie dennoch einen expliziten GC darin codieren (oder verwenden) (da ein Scheme-Heap Zirkularitäten aufweist). Und die meisten Proof-Assistenten sind aus guten Gründen in GC-ed-Sprachen codiert, häufig in funktionalen Sprachen (die einzige, die ich kenne und die in C ++ codiert ist, ist Lean ).
Übrigens bin ich daran interessiert, eine solche C ++ 17-Implementierung von Scheme zu finden (aber weniger daran interessiert, sie selbst zu codieren), vorzugsweise mit einigen Multithreading-Fähigkeiten.