2009-07-24 12 views
17

Eines der Dinge, die für mich während des Lernens von C++ (und Direct3D, aber vor einiger Zeit) verwirrend war, ist, wenn Sie ein Zeigerelement in einer Klasse verwenden sollten. Zum Beispiel kann ich eine Nicht-Zeigerdeklaration verwenden:C++ - wann sollte ich ein Zeigerelement in einer Klasse verwenden

private: 
    SomeClass instance_; 

Oder ich könnte eine Zeigerdeklaration

private: 
    Someclass * instance_ 

Und dann neu verwenden() verwende, auf sie im Konstruktor.

Ich verstehe, dass, wenn SomeClass von einer anderen Klasse, einem COM-Objekt oder einem ABC abgeleitet werden kann, dann sollte es ein Zeiger sein. Gibt es noch andere Richtlinien, die ich beachten sollte?

Antwort

17

Ein Zeiger hat folgende Vorteile:

a) Sie können eine verzögerte Initialisierung tun, dass das Objekt nur kurz vor der ersten realen Nutzung init bedeutet/erstellen.

b) Der Entwurf: Wenn Sie Zeiger für Member eines externen Klassentyps verwenden, können Sie eine Vorwärtsdeklaration über Ihre Klasse platzieren und müssen daher nicht die Header dieses Typs in Ihren Header aufnehmen Sie fügen die Header von Drittanbietern in Ihre .cpp-Datei ein. Dies hat den Vorteil, dass die Kompilierzeit verkürzt wird und Nebenwirkungen vermieden werden, indem zu viele andere Header hinzugefügt werden.

class ExtCamera; // forward declaration to external class type in "ExtCamera.h" 

class MyCamera { 
public: 
    MyCamera() : m_pCamera(0) { } 

    void init(const ExtCamera &cam); 

private: 
    ExtCamera *m_pCamera; // do not use it in inline code inside header! 
}; 

c) Ein Zeiger kann jederzeit gelöscht werden - so dass Sie mehr Kontrolle über die Lebenszeit haben und ein Objekt neu erstellen können - zum Beispiel im Fall eines Ausfalls.

+2

Für faul Initialisierung, würde ich 'Boost :: optional' wann immer möglich empfehlen. Es ist sicherer als Zeiger, weil Sie keine Arithmetik ausführen können. –

+1

Aber viele (wie ich) benutzen Boost nicht - das ist also eine sehr plattform- und rahmenunabhängige Art ;-) ... ich benutze zum Beispiel nur Qt :-) – 3DH

+1

Aber die, die 'boost' nicht verwenden sollten :) – GManNickG

10

Verteilen Sie es auf dem Stapel, wenn Sie können, aus dem Free-Store, wenn Sie müssen. Es gibt eine similar question hier, wo Sie alle "Why's" finden.

Der Grund, warum Sie viele Zeiger verwenden, wenn es um Spiele und Sachen geht, ist, weil DirectX eine COM-Schnittstelle ist, und in der Ehrlichkeit sind die meisten Spiele-Programmierer von damals nicht wirklich C++ - Programmierer, sie sind C- With-Class-Programmierer, und in C-Zeiger-Verwendung ist sehr üblich.

17

Die Vorteile der Verwendung eines Zeigers werden von 3DH umrissen: verzögerte Initialisierung, Reduzierung der Header-Abhängigkeiten und Kontrolle über die Lebensdauer des Objekts.

Die sind auch Nachteile. Wenn Sie über ein Zeigerdatenelement verfügen, müssen Sie wahrscheinlich Ihren eigenen Kopierkonstruktor und Zuweisungsoperator schreiben, um sicherzustellen, dass eine Kopie des Objekts ordnungsgemäß erstellt wird. Natürlich müssen Sie auch daran denken, das Objekt im Destruktor zu löschen. Wenn Sie einer vorhandenen Klasse ein Zeigerdatenelement hinzufügen, müssen Sie außerdem daran denken, den Kopierkonstruktor und operator = zu aktualisieren. Kurz gesagt, ein Zeiger Daten Mitglied ist mehr Arbeit für Sie.

Ein weiterer Nachteil ist wirklich die Kehrseite der Kontrolle über die Lebensdauer des Objekts, auf das der Zeiger zeigt. Nicht-Zeiger-Datenelemente werden automatisch zerstört, wenn das Objekt zerstört wird, was bedeutet, dass Sie immer sicher sein können, dass sie existieren, solange das Objekt existiert. Mit dem Zeiger müssen Sie überprüfen, ob es nullptr ist, was bedeutet, dass Sie auch sicherstellen müssen, dass es auf nullptr gesetzt wird, wenn es nichts zeigt. All dies zu bewältigen kann leicht zu Fehlern führen.

Schließlich ist der Zugriff auf Nicht-Zeiger-Mitglieder wahrscheinlich schneller, da sie zusammenhängend im Speicher sind. Auf der anderen Seite verursacht der Zugriff auf Zeigerdatenelemente, die auf ein Objekt zeigen, das auf dem Heap zugeordnet ist, wahrscheinlich einen Cache-Fehltreffer, wodurch dieser langsamer wird.

Es gibt keine einzige Antwort auf Ihre Frage. Sie müssen sich Ihr Design ansehen und entscheiden, ob die Vorteile von Zeigerdatenelementen die zusätzlichen Kopfschmerzen überwiegen. Wenn die Reduzierung von Kompilierungszeit und Headerabhängigkeiten wichtig ist, verwenden Sie die pimpl idiom. Wenn Ihr Datenelement in bestimmten Fällen für Ihr Objekt nicht erforderlich ist, verwenden Sie einen Zeiger und weisen Sie ihn bei Bedarf zu. Wenn diese nicht wie zwingende Gründe klingen, und Sie keine zusätzliche Arbeit machen wollen, dann verwenden Sie keinen Zeiger.

3

Ein weiterer Grund, Zeiger zu verwenden, wäre dynamische Bindung. Wenn Sie eine Basisklasse mit einer virtuellen Methode und einigen abgeleiteten Klassen haben, können Sie die dynamische Bindung nur über Zeiger erhalten.

+2

Das ist nicht ganz richtig - Sie können dynamische Bindung mit Referenzen haben. – boxofrats

+1

Sehr wahr, danke für die Klarstellung. –

Verwandte Themen