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.
Ich habe mit dem Embedded Symbian OS gearbeitet, das dafür ein exzellentes System auf Basis von Entwicklerkonventionen entwickelt hat.
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.
Regeln:
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 .
Ich würde hier eine weitere Regel hinzufügen:
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.
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.
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.
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