Share via


Intelligente Zeiger modernes (C++)

In modernen C++-Programmierung die Standardbibliothek enthält intelligente Zeiger, die verwendet werden, um sicherzustellen, dass Programme frei von Speicher und Ressource von Speicherverlusten und Ausnahme-sicher sind.

Anwendungen für intelligente Zeiger

Intelligente Zeiger werden definiert, der std -Namespace in der <memory> Header-Datei.Sie sind entscheidend für die RAII oder Resource-Acquisition ist Initialialization Programmierung Idiom.Das Hauptziel dieses Idiom ist sicherzustellen, dass die Ressourcenbelegung gleichzeitig auftritt, der das Objekt initialisiert wird, so dass alle Ressourcen für das Objekt erstellt und in einer einzigen Codezeile bereit gestellt.In der Praxis ist das wichtigste Prinzip der RAII, geben den Besitz jeder Heap zugeordnete Ressource – beispielsweise Speicher dynamisch zugewiesen oder System-Objekt-Handles – ein Stapel reserviert-Objekt, dessen Destruktor den Code zum Löschen oder frei enthält, die Ressource aus, und auch alle, verbundenen Bereinigungscode.

In den meisten Fällen Wenn Sie einen raw-Zeiger oder eine Ressource Handle auf eine Ressource hinzu initialisieren, übergeben Sie den Zeiger auf ein intelligenter Zeiger sofort.In modernen C++ sind Rawzeiger nur in kleinen Codeblöcke begrenzten Umfang, Schleifen oder Helper-Funktionen verwendet, wo Performance wichtig ist und es gibt keine Chance, Verwirrung über den Besitz.

Das folgende Beispiel vergleicht eine Erklärung unformatierten Zeiger auf eine intelligente Zeiger-Deklaration.

void UseRawPointer()
{
    // Using a raw pointer -- not recommended.
    Song* pSong = new Song(L"Nothing on You", L"Bruno Mars"); 

    // Use pSong...

    // Don't forget to delete!
    delete pSong;   
}


void UseSmartPointer()
{
    // Declare a smart pointer on stack and pass it the raw pointer.
    unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));

    // Use song2...
    wstring s = song2->duration_;
    //...

} // song2 is deleted automatically here.

Wie im Beispiel gezeigt, ist ein intelligenter Zeiger einer Klassenvorlage, die Sie auf dem Stapel deklarieren und initialisieren, indem Sie einen unformatierten Zeiger, der auf einem Heap zugeordnete Objekt verweist.Nach der Initialisierung des intelligenten Zeigers besitzt unformatierten Zeiger.Dies bedeutet, dass es sich bei der intelligente Zeiger ist verantwortlich für das Löschen des Speichers, der der unformatierte Zeiger angibt.Der Destruktor intelligenten Zeiger enthält den Aufruf zu löschen, und weil intelligente Zeiger auf dem Stapel deklariert wird, der Destruktor wird aufgerufen, wenn der intelligente Zeiger bewegt sich außerhalb des Bereichs, selbst wenn eine Ausnahme, irgendwo weiter oben im Stapel ausgelöst wird.

Den gekapselten Zeiger zugreifen, indem Sie mithilfe der Operatoren vertraut Zeiger -> und *, die intelligenten Zeiger-Klasse überlädt, um gekapselte Rawzeiger zurückzugeben.

Das C++ intelligenten Zeiger Idiom ähnelt der Objekterstellung in Sprachen wie c#: Erstellen Sie das Objekt und lassen Sie dann das System kümmern zum richtigen Zeitpunkt zu löschen.Der Unterschied besteht darin, dass keine separaten Garbage Collector im Hintergrund ausgeführt wird. Speicher wird durch die C++-Standardbibliothek scoping-Regeln so, dass die Laufzeitumgebung, schneller und effizienter ist verwaltet.

Wichtiger HinweisWichtig

Erstellen Sie intelligente Zeiger immer auf einer separaten Zeile der Code niemals in einer Parameterliste, so dass subtile Ressourcenverlusten aufgrund bestimmter Parameter Liste Verteilungsregeln auftreten wird nicht.

Das folgende Beispiel zeigt wie ein unique_ptr intelligenten Zeiger-Typ aus der Standard Template Library könnte verwendet werden, um einen Zeiger auf ein großes Objekt zu kapseln.


class LargeObject
{
public:
    void DoSomething(){}
};

void ProcessLargeObject(const LargeObject& lo){}
void SmartPointerDemo()
{    
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Pass a reference to a method.
    ProcessLargeObject(*pLarge);

} //pLarge is deleted automatically when function block goes out of scope.

Das Beispiel veranschaulicht die folgenden grundlegenden Schritte für die Verwendung von intelligenten Zeigern.

  1. Deklarieren Sie den intelligenten Zeiger als eine automatische (lokale) Variable.(Verwenden Sie nicht die new oder malloc Ausdruck für den intelligenten Zeiger selbst.)

  2. Geben Sie im Type-Parameter die hingewiesen, die gekapselten Zeiger.

  3. Übergeben von einen unformatierten Zeiger auf eine new-Ed-Objekt im Konstruktor einen intelligenten Zeigers.(Einige Hilfsfunktionen oder intelligenten Zeiger Konstruktoren dies für Sie tun.)

  4. Verwenden Sie die überladene -> und * Operatoren auf das Objekt zugreifen.

  5. Lassen Sie den intelligenten Zeiger, der das Objekt zu löschen.

Intelligente Zeiger sollen so effizient wie möglich, sowohl an Speicher und Leistung.Zum Beispiel die einzige Datenmember in unique_ptr der gekapselte Zeiger ist.Dies bedeutet, dass unique_ptr ist genau die gleiche Größe wie diesen Zeiger, vier Byte oder 8 Bytes.Zugreifen auf den gekapselten Zeiger mithilfe des intelligenten Zeigers überladen * und - > Operatoren ist nicht wesentlich langsamer als die direkten Zugriff auf die raw-Zeiger.

Intelligente Zeiger haben eigene Memberfunktionen, die mithilfe der Notation "Dot" zugegriffen werden.Beispielsweise haben einige STL intelligente Zeiger eine Reset-Memberfunktion, die Besitz des Zeigers frei.Dies ist nützlich, wenn der Speicher im Besitz von intelligenten Zeiger bevor der intelligente Zeiger bewegt sich außerhalb des Bereichs, wie im folgenden Beispiel gezeigt werden soll.

void SmartPointerDemo2()
{
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Free the memory before we exit function block.
    pLarge.reset();

    // Do some other work...

}

Intelligente Zeiger bieten in der Regel eine Möglichkeit, ihre unformatierten Zeiger direkt zugreifen.Intelligente Zeiger STL haben ein get -Memberfunktion für diesen Zweck und CComPtr hat eine öffentliche p Klassenmember.Durch die direkten Zugriff auf die zugrunde liegenden Zeiger, können Sie intelligenten Zeiger Speicher in Ihrem eigenen Code zu verwalten, und übergeben unformatierten Zeiger noch für Code, der intelligente Zeiger nicht unterstützt.

void SmartPointerDemo4()
{
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Pass raw pointer to a legacy API
    LegacyLargeObjectFunction(pLarge.get());    
}

Arten von intelligenten Zeigern

Der folgende Abschnitt fasst die verschiedenen Arten von intelligenten Zeigern, die in der Programmierumgebung Windows verfügbar sind und beschreibt deren Verwendung.

  • Standard C++ Library intelligente Zeiger
    Verwenden Sie diese intelligenten Zeigern zum Kapseln von Zeigern auf plain old C++-Objekte (POCO) als erste Wahl.

    • unique_ptr
      Ermöglicht es genau einen Besitzer des zugrunde liegenden Zeiger.Als Standardauswahl für POCO verwenden, es sei denn, Sie für bestimmte wissen, dass Sie eine shared_ptr.An einen neuen Eigentümer verschoben, aber nicht kopieren kann oder freigegeben.Ersetzt auto_ptr, die veraltet ist.Vergleichen Sie mit boost::scoped_ptr.unique_ptrist klein und effizient. die Größe ist ein Zeiger, und Rvalue Verweise für schnelle-Einfüge- und Abrufoperationen von STL-Auflistungen unterstützt.Header-Datei: <memory>.Weitere Informationen finden Sie unter Gewusst wie: Erstellen und verwenden Sie unique_ptr Instanzen und unique_ptr Class.

    • shared_ptr
      Verweiszählung intelligenten Zeiger.Verwenden, wenn Sie möchten einem unformatierten Zeiger mehrere Eigentümer zuweisen, wenn Sie eine Kopie eines Zeigers von einem Container zurück, aber das Original behalten möchten.Der unformatierte Zeiger wird nicht gelöscht, bis alle shared_ptr Besitzer außerhalb des Gültigkeitsbereichs gegangen oder anderweitig zuständig gegeben haben.Die Größe beträgt zwei Zeiger; eine für das Objekt und eine für die freigegebenen Control Block, die den Verweiszähler enthält.Header-Datei: <memory>.Weitere Informationen finden Sie unter Gewusst wie: Erstellen und verwenden Sie shared_ptr Instanzen und shared_ptr Class.

    • weak_ptr
      Special-Case intelligenten Zeiger für die Verwendung in Verbindung mit shared_ptr.A weak_ptr ermöglicht den Zugriff auf ein Objekt, das von einem oder mehreren gehört shared_ptr -Instanzen, aber nicht Verweiszählung an.Verwenden Sie ein Objekt zu beobachten, aber nicht erforderlich, es bleiben am Leben.In einigen Fällen benötigt werden, um Zirkelverweise zwischen brechen shared_ptr Instanzen.Header-Datei: <memory>.Weitere Informationen finden Sie unter Gewusst wie: Erstellen und verwenden Sie weak_ptr Instanzen und weak_ptr Class.

  • Intelligente Zeiger für COM-Objekte (klassische Windows-Programmierung)
    Beim Arbeiten mit COM-Objekten, wickeln Sie die Schnittstellenzeiger in einem geeigneten, intelligenten Zeiger-Typ.Die Active Template Library (ATL) definiert verschiedene intelligente Zeiger für verschiedene Zwecke.Sie können auch die _com_ptr_t smart Pointer-Type, die der Compiler verwendet, wenn sie Wrapper-Klassen aus .tlb-Dateien erstellt.Es ist die beste Wahl, wenn Sie nicht die ATL-Headerdateien einlesen möchten.

  • ATL-intelligente Zeiger für POCO-Objekte
    Zusätzlich zu den intelligenten Zeigern für COM-Objekte definiert ATL auch intelligente Zeiger und Sammlungen von intelligenten Zeigern für plain old C++-Objekte.In der klassischen Windows-Programmierung sind solche hilfreiche Alternativen zu den STL-Auflistungen, vor allem, wenn die Codeportabilität nicht erforderlich ist oder wenn Sie nicht die Programmiermodellen STL und ATL mischen

    • CAutoPtr-Klasse
      Intelligente Zeiger, der eindeutig den Besitz durch Übertragen des Besitzes auf Copy erzwingt.Vergleichbar mit der veralteten std::auto_ptr Klasse.

    • CHeapPtr-Klasse
      Intelligente Zeiger für Objekte, die reserviert sind, mit die c malloc Funktion.

    • CAutoVectorPtr-Klasse
      Intelligente Zeiger für Arrays, die mit zugewiesen werden new[].

    • CAutoPtrArray-Klasse
      Klasse, die kapselt ein Array von CAutoPtr Elemente.

    • CAutoPtrList-Klasse
      Klasse, die Methoden zum Bearbeiten einer Liste der kapselt CAutoPtr Knoten.

Siehe auch

Weitere Ressourcen

Willkommen zurück in C++ modernes (C++)

C++-Sprachreferenz

C++-Standardbibliothek-Referenz

Übersicht: Speicherverwaltung in C++