Menschen, die es gewohnt sind, gesammelte Sprachen zu löschen, haben häufig Angst vor der Speicherverwaltung in C ++. Es gibt Werkzeuge, wie auto_ptr
und shared_ptr
welche viele der Speicherverwaltungsaufgaben für Sie behandelt. Viele C ++ - Bibliotheken sind älter als diese Tools und können die Speicherverwaltungsaufgaben auf ihre eigene Weise ausführen.
Wie viel Zeit verbringen Sie mit Speicherverwaltungsaufgaben?
Ich vermute, dass dies in hohem Maße von der Menge der von Ihnen verwendeten Bibliotheken abhängt. Sagen Sie daher bitte, auf welche Bibliotheken Ihre Antwort zutrifft und ob sie diese verbessern oder verschlechtern.
Antworten:
In modernem C ++ müssen Sie sich erst um die Speicherverwaltung kümmern, wenn Sie dies tun müssen. Dies gilt vor allem für Optimierungszwecke oder wenn der Kontext Sie dazu zwingt (denken Sie an Hardware mit großen Einschränkungen). Ich habe ganze Spiele geschrieben, ohne das rohe Gedächtnis zu manipulieren, und mich nur darum gekümmert, Container zu verwenden, die das richtige Werkzeug für den Job sind, wie in jeder Sprache.
Es hängt also vom Projekt ab, aber die meiste Zeit müssen Sie nicht mit der Speicherverwaltung befassen, sondern nur mit der Objektlebensdauer. Dies wird mit intelligenten Zeigern gelöst , einem idiomatischen C ++ - Tool, das aus RAII resultiert .
Sobald Sie RAII verstanden haben , ist die Speicherverwaltung kein Problem mehr.
Wenn Sie dann auf den Raw-Speicher zugreifen müssen, tun Sie dies in sehr spezifischem, lokalisiertem und identifizierbarem Code, wie bei Pool-Objekt-Implementierungen, nicht "überall".
Außerhalb dieser Art von Code müssen Sie nicht den Speicher manipulieren, sondern nur die Lebensdauer der Objekte.
Der "schwierige" Teil ist, RAII zu verstehen.
quelle
delete
manuell, es sei denn, Sie haben eine beschissene Implementierung.return
).Speicherverwaltung wird verwendet, um Kinder zu erschrecken, aber es ist nur eine Art von Ressource, um die sich ein Programmierer kümmern muss. Denken Sie an Dateihandles, Netzwerkverbindungen und andere Ressourcen, die Sie vom Betriebssystem erhalten.
Die Sprachen, die die Garbage Collection unterstützen, ignorieren in der Regel nicht nur die Existenz dieser Ressourcen, sondern erschweren auch deren ordnungsgemäßen Umgang, indem sie keinen Destruktor bereitstellen.
Kurz gesagt, ich würde nicht vorschlagen, dass ein C ++ - Entwickler viel Zeit damit verbringt, sich um die Speicherverwaltung zu kümmern. Wie die Antwort von klaim zeigt, ist der Rest nur ein Reflex, sobald Sie RAII in den Griff bekommen.
quelle
finalize
Konstrukt. Sie wissen jedoch nicht, wann es aufgerufen wird. Wird es sein, bevor Ihnen die Sockets oder WebResponse-Objekte ausgehen? In zahlreichen Artikeln erfahren Sie, auf welche Sie sich nicht verlassen solltenfinalize
- aus gutem Grund.So ziemlich keine. Selbst mit alten Technologien wie COM können Sie benutzerdefinierte Deleter für die Standard-Zeiger schreiben, die sie in kürzester Zeit konvertieren. Zum Beispiel
std::unique_ptr
kann einen COM - Verweis mit fünf Zeilen eines benutzerdefinierten deleter eindeutig halten umgewandelt werden. Selbst wenn Sie Ihren eigenen Ressourcen-Handler manuell schreiben müssen, macht es die Verbreitung von Wissen wie SRP und Copy-and-Swap relativ einfach, eine Ressourcen-Verwaltungsklasse zu schreiben, die für immer mehr verwendet werden kann.Die Realität ist, dass Ihr C ++ 11-Compiler gemeinsam genutzt wird, einzigartig ist und keine Eigentumsrechte besitzt. Sie müssen nur kleine Adapter schreiben, damit sie auch mit altem Code funktionieren.
quelle
Als ich (vor langer Zeit) ein C ++ - Programmierer war, machte ich mir lange Gedanken über Speicherverwaltungsfehler, wenn ich versuchte, schwer reproduzierbare Fehler zu beheben .
Mit Modem C ++ ist die Speicherverwaltung weniger ein Problem, aber Sie können jedem in einem großen Team vertrauen, dass er es richtig macht. Was kostet / Zeit von:
Es ist also nicht nur die Zeit, die für das „ Tun “ aufgewendet wird , dies ist eher ein Problem bei großen Projekten.
quelle
Ich benutze oft Boost- und TR1-Bibliotheken und sie machen die Speicherverwaltung im engeren Sinne (neu / löschen) zu einem Nicht-Problem. Andererseits ist die Speicherzuweisung in C ++ nicht billig, und man muss darauf achten, wo diese ausgefallenen gemeinsamen Zeiger erstellt werden. Sie belegen häufig Arbeitsbereiche oder arbeiten mit stapelbasiertem Speicher. Im Allgemeinen würde ich sagen, dass es sich hauptsächlich um ein Designproblem und nicht um ein Implementierungsproblem handelt.
quelle
Wie lange dauert es als Kunde? sehr wenig, sobald Sie den Dreh raus haben. Wenn ein Container die Lebensdauer und Referenzen verwaltet, ist das wirklich sehr einfach. imo, es ist viel einfacher als das manuelle Zählen von Verweisen, und es ist praktisch transparent, wenn Sie den Container, den Sie als Dokumentation verwenden, betrachten, wodurch der Compiler bequem verhindert, dass Sie ungültige Eigentumsübertragungen in einem gut gestalteten typsicheren System durchführen.
Die meiste Zeit, die ich (als Client) verbringe, wird mit Typen von anderen APIs verbracht, sodass sie im Kontext Ihrer Programme gut funktionieren. Beispiel: Dies ist mein ThirdPartyFont-Container. Er unterstützt diese Funktionen und implementiert die Zerstörung auf diese Weise und die Referenzzählung auf diese Weise und das Kopieren auf diese Weise . Viele dieser Konstrukte müssen vorhanden sein, und oft ist es der logische Ort, sie zu platzieren. ob Sie dies als Zeitangabe angeben möchten oder nicht, hängt von Ihrer Definition ab (die Implementierung muss für die Schnittstelle zu diesen APIs ohnehin vorhanden sein, oder?).
Danach müssen Sie Gedächtnis und Besitz berücksichtigen. In einem untergeordneten System ist das gut und notwendig, aber es kann einige Zeit und ein Gerüst dauern, um zu implementieren, wie Sie die Dinge bewegen sollten. ich sehe es nicht als schmerz an, da dies eine anforderung eines untergeordneten systems ist. Eigentum, Kontrolle und Verantwortung sind offensichtlich.
So können wir dies auf c-basierte APIs umstellen, die undurchsichtige Typen verwenden: Mit unseren Containern können wir alle Details der Implementierung zum Verwalten der Lebensdauer und zum Kopieren dieser undurchsichtigen Typen zusammenfassen. Dies macht die Ressourcenverwaltung letztendlich sehr einfach und spart Zeit und Fehler. und reduziert Implementierungen.
Es ist wirklich sehr einfach, diese zu verwenden - das Problem (von GC kommend) ist, dass Sie jetzt die Lebensdauer Ihrer Ressourcen berücksichtigen müssen. Wenn Sie etwas falsch machen, kann die Lösung viel Zeit in Anspruch nehmen. Das Erlernen und Integrieren von explizitem Lebensdauermanagement ist im Vergleich verständlicherweise komplex (nicht für alle Menschen) - das ist die eigentliche Hürde. Wenn Sie erst einmal die Lebensdauern im Griff haben und gute Lösungen verwenden, ist es wirklich sehr einfach, die Lebensdauern von Ressourcen zu verwalten. Es ist kein wesentlicher Teil meines Tages (es sei denn, ein schwieriger Fehler hat sich eingeschlichen).
Wenn Sie keine Container verwenden (Auto / Shared Pointer), bitten Sie nur um Schmerz.
Ich habe meine eigenen Bibliotheken implementiert. es nimmt mir Zeit , um diese Dinge zu implementieren, aber die meisten Menschen wieder verwenden (was in der Regel eine gute Idee ist).
quelle
Sie möchten gerne manuell Speicher freigeben, Dateien schließen, solche Dinge? In diesem Fall würde ich das Minimum und normalerweise weniger als die meisten anderen Sprachen angeben, die ich verwendet habe, insbesondere wenn wir dies nicht nur auf "Speicherverwaltung", sondern auf "Ressourcenverwaltung" verallgemeinern. In diesem Sinne glaube ich, dass C ++ weniger manuelle Ressourcenverwaltung erfordert als beispielsweise Java oder C #.
Dies ist hauptsächlich auf Destruktoren zurückzuführen, die das Zerstören der Ressource (Speicher oder auf andere Weise) automatisieren. Normalerweise muss ich eine Ressource in C ++ nur dann manuell freigeben / zerstören, wenn ich eine Datenstruktur auf Vlow-Ebene implementiere (was die meisten Leute nicht tun müssen) oder eine C-API verwende, in der ich nur ein wenig Zeit verbringe Umhüllen der C-Ressource, die manuell freigegeben / zerstört / geschlossen werden muss, in einen RAII-konformen C ++ - Wrapper.
Wenn ein Benutzer ein Bild in einer Bildbearbeitungssoftware schließen möchte, muss ich das Bild natürlich aus einer Sammlung entfernen. Aber hoffentlich zählt das nicht als "Speicher" - oder "Ressourcen" -Verwaltung, wie es in diesem Zusammenhang von Bedeutung ist, da dies in jeder Sprache so ziemlich erforderlich ist, wenn Sie den Speicher freigeben möchten, der zu diesem Zeitpunkt mit diesem Bild verknüpft ist. Aber alles, was Sie tun müssen, ist, das Bild aus der Sammlung zu entfernen, und der Bildzerstörer kümmert sich um den Rest.
Wenn ich es mit Java oder C # vergleiche, muss man häufig Dateien manuell schließen, Sockets manuell trennen, Objektreferenzen auf null setzen, damit sie vom Müll gesammelt werden können, usw. Es gibt viel mehr manuellen Speicher und Ressourcenverwaltung in diesen Sprachen, wenn Sie mich fragen. In C ++ müssen Sie häufig nicht einmal
unlock
manuell einen Mutex erstellen, da der Mutex-Locker dies automatisch für Sie erledigt, wenn der Mutex den Gültigkeitsbereich verlässt. Zum Beispiel sollten Sie in C ++ niemals so etwas tun müssen:Es ist nicht erforderlich, Dateien in C ++ manuell zu schließen. Sie schließen sich automatisch, sobald sie den Gültigkeitsbereich verlassen, unabhängig davon, ob sie das Ergebnis oder normale oder außergewöhnliche Ausführungspfade sind. Ähnliches gilt für speicherbezogene Ressourcen wie
std::vector
. Ein solcher Code wiefile.Close()
oben wird oft missbilligt, da er insbesondere im Zusammenhang mit einemfinally
Block darauf hindeutet, dass die lokale Ressource manuell freigegeben werden muss, wenn die gesamte Denkweise in C ++ dies automatisieren soll.In Bezug auf die manuelle Speicherverwaltung würde ich sagen, dass C das Maximum, Java / C # eine mittlere Menge und C ++ das Minimum von diesen erfordert. Es gibt viele Gründe, etwas schüchtern mit C ++ umzugehen, da es eine sehr schwierig zu beherrschende Sprache ist, aber die Speicherverwaltung sollte keine davon sein. Im Gegenteil, ich denke tatsächlich, dass es in dieser Hinsicht eine der einfachsten Sprachen überhaupt ist.
Natürlich können Sie in C ++ den Speicher manuell zuweisen und aufrufen
operator delete/delete[]
, um Speicher manuell freizugeben. Sie können auch C-Funktionen wiemalloc
und verwendenfree
. Aber das sind Codierungspraktiken im alten Stil, von denen ich denke, dass sie veraltet sind, lange bevor die Leute Anerkennung finden, da Stroustrup RAII befürwortet hat, bevor er den Begriff überhaupt von Anfang an geprägt hat. Ich halte es also nicht einmal für fair zu sagen, dass "modernes C ++" das Ressourcenmanagement automatisiert, weil dies eigentlich der ganze Zweck sein sollte. Sie können sonst praktisch keine Ausnahmesicherheit erhalten. Es ist nur so, dass viele fehlgeleitete Entwickler in den frühen 90ern versucht haben, C ++ wie C mit Objekten zu verwenden, und dabei die Ausnahmebehandlung oft völlig ignoriert haben, und es sollte nie so verwendet werden. Wenn Sie C ++ so verwenden, wie es eigentlich immer beabsichtigt war, dann ist die Speicherverwaltung vollständig automatisiert und im Allgemeinen nicht etwas, mit dem Sie manuell zu tun haben (oder mit dem Sie zu tun haben sollten).quelle
Hängt von den technischen Führungskräften im Team ab. In einigen Unternehmen (einschließlich meiner) gibt es kein Konzept namens Smart Poiner. Es gilt als schick. Daher werden Löschvorgänge einfach überall abgelegt, und alle 2 Monate wird ein Laufwerk zur Behebung von Speicherlecks eingerichtet. Überall kommt eine neue Welle von Löschanweisungen an. Kommt also auf die Firma und die Art der Leute an, die dort arbeiten.
quelle
auto_ptr
und Ihre Freunde davon abhält, es zu benutzen ?