C ++ Speicherverwaltung

8

Ich habe im College gelernt, dass du immer deine unbenutzten Objekte freilassen musst, aber nicht wie du es tust. Zum Beispiel Strukturieren Sie Ihren Code richtig und so weiter. Gibt es allgemeine Regeln für die Behandlung von Zeigern in C ++?

Ich darf momentan keinen Boost verwenden. Ich muss bei reinem C ++ bleiben, weil das verwendete Framework die Verwendung von Generika verbietet.

    
Alexander Stolz 26.08.2008, 06:50
quelle

8 Antworten

14

Ich habe mit dem Embedded Symbian OS gearbeitet, das dafür ein exzellentes System auf Basis von Entwicklerkonventionen entwickelt hat.

  1. Nur ein Objekt besitzt jemals einen Zeiger. Standardmäßig ist dies der Ersteller.
  2. Besitz kann weitergegeben werden. Um die Übergabe des Eigentums anzugeben, wird das Objekt als Zeiger in der Methodensignatur übergeben (z. B. void Foo (Bar * zonk);).
  3. Der Eigentümer entscheidet, wann das Objekt gelöscht werden soll.
  4. Um ein Objekt an eine einfach zu verwendende Methode zu übergeben, wird das Objekt als Referenz in der Methodensignatur übergeben (z. B. void Foo (Bat & amp; zonk);).
  5. Nicht-Besitzer-Klassen können Referenzen (niemals Zeiger) auf Objekte speichern, die ihnen nur dann gegeben werden, wenn sie sicher sein können, dass der Besitzer sie während der Verwendung nicht zerstört.

Wenn eine Klasse einfach etwas verwendet, verwendet sie eine Referenz. Wenn eine Klasse etwas besitzt, verwendet sie einen Zeiger.

Das hat wunderbar funktioniert und es war eine Freude es zu benutzen. Speicherprobleme waren sehr selten.

    
Sander 26.08.2008, 07:08
quelle
5

Regeln:

  1. Wo immer möglich, benutze a intelligenter Zeiger . Boost hat einige gute .
  2. Wenn du kann keinen intelligenten Zeiger verwenden, null aus Ihr Zeiger nach dem Löschen .
  3. Arbeiten Sie niemals irgendwo, wo Sie Regel 1 nicht verwenden können.

Wenn jemand Regel 1 nicht zulässt, denken Sie daran, dass Sie, wenn Sie sich den Code von jemand anderem nehmen, die Namen der Variablen ändern und die Copyright-Hinweise löschen, niemand wird es jemals bemerken. Es sei denn, es handelt sich um ein Schulprojekt, bei dem sie mit ziemlich ausgefeilten Werkzeugen nach solchen Scherzen suchen. Siehe auch diese Frage .

    
Josh 26.08.2008 06:52
quelle
3

Ich würde hier eine weitere Regel hinzufügen:

  • Nicht neu / löschen Sie ein Objekt, wenn ein automatisches Objekt gut funktioniert.

Wir haben festgestellt, dass Programmierer, die neu in C ++ sind oder Programmierer, die aus Sprachen wie Java kommen, etwas Neues lernen und dann zwanghaft verwenden, wenn sie ein beliebiges Objekt unabhängig vom Kontext erstellen wollen. Dies ist besonders schädlich, wenn ein Objekt lokal innerhalb einer Funktion erstellt wird, um etwas Nützliches zu tun. Die Verwendung von new auf diese Weise kann sich nachteilig auf die Leistung auswirken und es zu leicht machen, dumme Speicherlecks einzuführen, wenn das entsprechende Löschen vergessen wird. Ja, intelligente Zeiger können mit letzterem helfen, aber es wird die Leistungsprobleme nicht lösen (vorausgesetzt, dass new / delete oder ein Äquivalent im Hintergrund verwendet wird). Interessanterweise (naja, vielleicht) haben wir festgestellt, dass delete bei Verwendung von Visual C ++ oft teurer ist als neu.

Einige dieser Verwirrungen ergeben sich auch aus der Tatsache, dass Funktionen, die sie aufrufen, Zeiger oder sogar intelligente Zeiger als Argumente annehmen können (wenn Referenzen vielleicht besser / klarer wären). Das bringt sie dazu, zu denken, dass sie einen Zeiger "erstellen" müssen (viele Leute scheinen zu denken, dass dies das Neue ist), um einen Zeiger auf eine Funktion zu übergeben. Dies erfordert natürlich einige Regeln, wie APIs geschrieben werden, um Aufrufkonventionen so eindeutig wie möglich zu machen, die durch klare Kommentare, die mit dem Funktionsprototyp geliefert werden, verstärkt werden.

    
Nick 26.08.2008 17:09
quelle
2

Im allgemeinen Fall (Ressourcenverwaltung, wo Ressource nicht unbedingt Speicher ist), müssen Sie mit dem RAII-Muster vertraut sein . Dies ist eine der wichtigsten Informationen für C ++ - Entwickler.

    
On Freund 26.08.2008 07:37
quelle
2

Vermeiden Sie im Allgemeinen die Zuweisung aus dem Heap, es sei denn, Sie müssen dies tun. Wenn Sie müssen, verwenden Sie Referenzzählung für Objekte, die langlebig sind und zwischen verschiedenen Teilen Ihres Codes geteilt werden müssen.

Manchmal müssen Sie Objekte dynamisch zuweisen, aber sie werden nur innerhalb einer bestimmten Zeitspanne verwendet. Zum Beispiel musste ich in einem früheren Projekt eine komplexe In-Memory-Darstellung eines Datenbankschemas erstellen - im Grunde ein komplexer zyklischer Graph von Objekten. Das Diagramm wurde jedoch nur für die Dauer einer Datenbankverbindung benötigt, nach der alle Knoten auf einmal freigegeben werden konnten. In einem solchen Szenario ist ein gutes Muster, das ich nenne, das "lokale GC-Idiom". Ich bin mir nicht sicher, ob es einen "offiziellen" Namen hat, da es etwas ist, das ich nur in meinem eigenen Code und in Cocoa gesehen habe (siehe NSAutoreleasePool in Apples Cocoa-Referenz).

Kurz gesagt, Sie erstellen ein "Collector" -Objekt, das Zeiger auf die temporären Objekte behält, die Sie mit new zuweisen. Es ist normalerweise an einen Bereich in Ihrem Programm gebunden, entweder an einen statischen Bereich (z. B. - als ein stack-allokiertes Objekt, das das RAII-Idiom implementiert) oder an einen dynamischen (z. B. an die Lebensdauer einer Datenbankverbindung gebunden) mein vorheriges Projekt). Wenn das Objekt "collector" freigegeben wird, gibt sein Destruktor alle Objekte frei, auf die es zeigt.

Auch, wie DrPizza denke ich, ist die Einschränkung, keine Vorlagen zu verwenden, zu hart. Nachdem ich jedoch sehr viel an alten Versionen von Solaris, AIX und HP-UX entwickelt habe (erst kürzlich - diese Plattformen sind noch in den Fortune 50-Systemen), kann ich Ihnen sagen, dass Sie, wenn Sie wirklich an Portabilität interessiert sind sollte Vorlagen so wenig wie möglich verwenden. Sie für Container und Smartpointer zu verwenden, sollte aber in Ordnung sein (es hat für mich funktioniert). Ohne Vorlagen ist die beschriebene Technik schwieriger zu implementieren. Es würde erfordern, dass alle vom "Collector" verwalteten Objekte von einer gemeinsamen Basisklasse abstammen.

    
Bruce Johnston 26.08.2008 19:18
quelle
1

Heute,

Ich würde empfehlen, die relevanten Abschnitte von "Effective C ++" von Scott Meyers zu lesen. Leicht zu lesen und er deckt einige interessante Fälle ab, um die Unachtsamen zu fangen.

Ich bin auch fasziniert von dem Mangel an Vorlagen. Also kein STL oder Boost. Wow.

BTW Leute dazu zu bringen, sich auf Konventionen zu einigen, ist eine ausgezeichnete Idee. Wie man alle dazu bringt, sich auf Konventionen für OOD zu einigen. BTW Die neueste Ausgabe von Effective C ++ hat nicht das ausgezeichnete Kapitel über OOD-Konventionen, das die erste Ausgabe hatte, was schade ist, z.B. Konventionen wie öffentliche virtuelle Vererbung immer modelliert eine "isa" -Beziehung.

Rob

    
Rob Wells 26.08.2008 09:39
quelle
0
  • Wenn Sie Speicher verwalten verwenden müssen manuell, stellen Sie sicher, dass Sie löschen aufrufen im gleichen Umfang / Funktion / Klasse / Modul, die gilt zuerst, z. B .:
  • Lassen Sie den Aufrufer einer Funktion den Speicher zuordnen, der damit gefüllt ist, gib keine neuen Zeiger zurück.
  • Rufen Sie immer delete in der gleichen exe / dll auf, in der Sie new in aufgerufen haben, da Sie sonst Probleme mit Heap-Fehlern (verschiedene inkompatible Laufzeitbibliotheken) haben könnten.
Timbo 26.08.2008 07:06
quelle
0

Sie könnten alles von einer Basisklasse ableiten, die eine intelligente Zeiger-ähnliche Funktionalität implementiert (mit ref () / unref () Methoden und einem Zähler.

)

Alle Punkte, die von @Timbo hervorgehoben werden, sind beim Entwerfen dieser Basisklasse wichtig.

    
mkrus 26.08.2008 08:19
quelle

Tags und Links