Ich bin relativ neu in einigen der fortgeschrittenen Aspekte der C ++ - Programmierung und ich habe ein paar Probleme zu verstehen, wenn es wirklich wirklich notwendig ist, Speicher in C ++ zu reservieren (ob durch malloc, neu, etc.). Zum Beispiel in C, ich verstehe, dass Sie Speicher reservieren müssen, um ein dynamisch sortiertes Array oder andere Aufgaben zu haben. In C ++ scheint mir das nicht der Fall zu sein. Sie können einfach eine std :: vector, std :: string oder andere eingebaute Methoden verwenden, die bereits dynamisch nach Größe sortiert sind. Ich verstehe auch, dass der Zugriff auf zugewiesenen Speicher langsamer ist als der Stapel.
Gibt es also Zeiten, in denen Sie Speicher in C ++ zuweisen müssen, und wenn ja, was ist ein Beispiel für eine dieser Zeiten? Dies beinhaltet natürlich keine Zeiten, in denen Ihr C ++ Code mit einem C-Programm interagieren muss. Nehmen wir an, das Programm ist rein in C ++ geschrieben.
EDIT: Um Verwirrung zu vermeiden, verstehe ich, dass Vektoren und andere Strukturen ihren eigenen Speicher zuweisen, aber das passiert hinter den Kulissen und erfordert nicht, dass der Programmierer neu, malloc usw. verwendet und es wird bereinigt automatisch auf. Also was ich wirklich frage ist, ist es jemals notwendig, Speicherverwaltung manuell in C ++ durchzuführen
Der Stapel ist von begrenzter Größe, einige Dinge passen einfach nicht zuverlässig hinein. Dynamisch zugeordneter Speicher hat auch die dynamische Natur, in der Sie manchmal nicht sicher sind, wie viele Objekte oder Elemente in einem Array Sie bis zu einem bestimmten Zeitpunkt der Ausführung des Programms benötigen.
Sehen Sie sich diese Frage an, es ist sehr gut möglich, dies zu beschreiben Anwendungsfälle für jedes:
Heap-Zuordnungen (dynamisch zugeordneter Speicher) sind nützlich, wenn Sie flexibler als oben sein möchten. Häufig wird eine Funktion aufgerufen, um auf ein Ereignis zu reagieren (der Benutzer klickt auf die Schaltfläche "create box"). Die richtige Antwort erfordert möglicherweise das Zuweisen eines neuen Objekts (ein neues Box-Objekt), das lange nach dem Beenden der Funktion bleiben sollte, so dass es nicht auf dem Stapel sein kann. Aber Sie wissen nicht, wie viele Boxen Sie am Anfang des Programms haben möchten, also kann es nicht statisch sein.
Um Ihre Bearbeitung zu reflektieren: In der Tat ist es nicht wirklich erforderlich, oder vielmehr, es ist in der Regel abstrahiert, wie es bei vector
und string
der Fall ist. Sie haben verschiedene Container wie vector
, die das für Sie erledigen. Wenn Sie Ihre eigenen Klassen entwerfen, werden Sie ermutigt, die Technik der Ressourcenzuweisung ist Initialisierung (RAII) anzuwenden, die abstrahiert die typische manuelle Speicherverwaltung. In bestimmten Fällen, besonders wenn Sie mit C-Code arbeiten, sollten Sie diesen Speicher entweder in einem C ++ - Klassenwrapper mit RAII oder mit einem C ++ - Smartpointer, wie er in C ++ 11 eingeführt wurde, verwalten: shared_ptr
und unique_ptr
(die selbst RAII verwenden).
Zum Beispiel in C, ich verstehe, dass Sie Speicher zuweisen müssen, um ein dynamisch sortiertes Array oder andere Aufgaben zu haben. In C ++ scheint mir das nicht der Fall zu sein, Sie können einfach einen std :: vector oder andere eingebaute Methoden verwenden, die bereits dynamisch nach dem Design dimensioniert sind.
std::vector
baut jedoch nicht auf Magie und Feenstaub auf: es reserviert intern Speicher.
Sie haben recht, dass Sie in C ++ nur selten manuell Speicher zuweisen müssen . Es gibt Fälle, wo das der einfachste Weg ist, obwohl 1 . Der Punkt ist, dass C ++ die manuelle Aufhebung der Zuordnung komplett überflüssig macht, da Destruktoren dafür sorgen werden.
1 Sehr, sehr selten. Der am besten geschriebene Code wird das überhaupt nicht brauchen. Es ist gelegentlich nützlich, wenn Sie mit Details auf niedrigeren Ebenen arbeiten (z. B. wenn Sie einen Container implementieren).
Wenn Ihre Frage lautet, " Ist dynamisch zugeordneter Speicher in C ++ unnötig? " Die Antwort ist, dass es sehr notwendig und sehr wichtig ist.
Wenn Ihre Frage wie folgt lautet: " Verwenden Sie moderne C ++ 11-Klassen und -Funktionen, wie häufig wird mein Code erfordern, dass ich manuell new und delete ' "?
Die Antwort darauf ist "selten". Die meisten neuen und gelöschten Aufrufe werden in Containern versteckt ( std :: vector , std :: map , ua) und Smartpointern ( std :: shared_ptr und std :: unique_ptr ) und durch Aufrufe von Funktionen wie std :: make_shared () .
Werden Sie in seltenen Fällen "neu" und "löschen" manuell aufrufen müssen? Es hängt von der Art des Programms ab, das du machst, aber wenn es sich um Videospiele handelt, würde ich sagen: Ja, wahrscheinlich 1% der Zeit (meine Erfahrung, aber YMMV), du musst manuell neu und löschen über std :: make_shared () und std :: shared_ptr - obwohl es wieder von dem Projekt abhängt.
Im Allgemeinen bevorzugen Sie lokale Variablen und Membervariablen, die auf dem Stack zugewiesen sind (ignorieren, wenn sie intern dynamischen Speicher zuweisen), bevorzugen als Nächstes C ++ 11 verwalteten dynamischen Speicher (Smartpointer), greifen schließlich auf neu und löschen als letztes Mittel, wenn die Leistung es erfordert (aber nicht voroptimieren - Profil und die echten Engpässe finden) .
Beachten Sie, nur weil Sie Ihren Speicher mit intelligenten Zeigern verwalten, bedeutet das nicht, dass Sie alle rohen Zeiger aus Ihrem Code verbannen sollten - selbst wenn all Ihr Speicher verwaltet wird, ist er immer noch sehr nützlich für rohe Zeiger, die nichts damit zu tun haben Speicherlebensdauerverwaltung.
Wie Sie gesehen haben, ist es nie notwendig, new
mit Standardcontainern zu verwenden ( vector
, map
, etc.)
Bei Verwendung von Smartpointern ist es immer besser, make_shared
als new
in ein shared_ptr
zu verwenden; für unique_ptr
ist das Fehlen von make_unique
ein Fehler ( make_unique und perfekte Weiterleitung ) ) die bald angesprochen werden sollten; es ist besser, Copy-Paste und% make_unique
als new
in unique_ptr
s selbst zu verwenden, aus Gründen der Klarheit und der Ausnahmesicherheit.
Wenn Sie Ihre eigenen Container schreiben, versuchen Sie nach Möglichkeit, Standardbibliotheken (existierende Container und Smart Pointer) zu erstellen, so dass Sie sich nicht um die Lebensdauerverwaltung kümmern müssen.
Es gibt eine Standardeinrichtung, bei der die Verwendung von new
erwartet wird; Der Vorlagenkonstruktor von std::locale
, der standardmäßig ein Facet *
verwendet, erwartet ein Facet *
, das von new
zugewiesen wurde, da es mit delete static_cast<locale::facet*>(f)
entsorgt wird, wenn es nicht mehr von std::locale
instances verwendet wird. (Beachten Sie, dass std::locale::facet
über einen virtuellen Destruktor verfügt.) Wenn Sie sich dadurch unwohl fühlen, können Sie die Lebensdauer der Facette selbst verwalten, indem Sie beim Erstellen der Facette 1
als Parameter refs
übergeben: Besitz / Löschen der Facette in einem Gebietsschema (std :: locale) .
Sie brauchen nicht zu sich selbst. Ich habe immer etwas wie das Folgende gemacht:
%Vor%Im Wesentlichen befinden sich einzelne Werte auf dem Stapel, während sich eine Sammlung auf dem Stapel befindet, aber alles auf einen Haufen stellt. Ich benutze nie das neue Schlüsselwort oder die neuen Zeiger in den meisten meiner Apps.
Tags und Links memory c++ memory-management