Frage Was ist ein intelligenter Zeiger und wann sollte ich einen verwenden?


Was ist ein intelligenter Zeiger und wann sollte ich einen verwenden?


1427
2017-09-20 00:09


Ursprung


Antworten:


Ein intelligenter Zeiger ist eine Klasse, die einen "rohen" (oder "nackten") C ++ - Zeiger umschließt, um die Lebensdauer des Objekts zu verwalten, auf das gezeigt wird. Es gibt keinen einzelnen intelligenten Zeigertyp, aber alle versuchen, einen rohen Zeiger auf praktische Weise zu abstrahieren.

Intelligente Zeiger sollten gegenüber rohen Zeigern bevorzugt werden. Wenn Sie das Gefühl haben, dass Sie Zeiger verwenden müssen (überlegen Sie zuerst, ob Sie Ja wirklich do), würden Sie normalerweise einen intelligenten Zeiger verwenden wollen, da dies viele der Probleme mit rohen Zeigern lindern kann, hauptsächlich vergessen, das Objekt zu löschen und Speicher zu verlieren.

Bei rohen Zeigern muss der Programmierer das Objekt explizit zerstören, wenn es nicht mehr nützlich ist.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Ein intelligenter Zeiger durch Vergleich definiert eine Richtlinie, wann das Objekt zerstört wird. Sie müssen das Objekt noch erstellen, aber Sie müssen sich nicht länger darum kümmern, es zu zerstören.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

Die einfachste verwendete Richtlinie umfasst den Bereich des Smart-Pointer-Wrapper-Objekts, z. B. implementiert durch boost::scoped_ptr oder std::unique_ptr.

void f()
{
    {
       boost::scoped_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // boost::scopted_ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Beachten Sie, dass scoped_ptr Instanzen können nicht kopiert werden. Dies verhindert, dass der Zeiger mehrmals (falsch) gelöscht wird. Sie können jedoch Referenzen zu anderen aufgerufenen Funktionen übergeben.

Bereichszeiger sind nützlich, wenn Sie die Lebensdauer des Objekts an einen bestimmten Codeblock binden möchten oder wenn Sie ihn als Elementdaten in ein anderes Objekt eingebettet haben, also die Lebensdauer dieses anderen Objekts. Das Objekt existiert, bis der umschließende Codeblock verlassen wird oder bis das umschließende Objekt selbst zerstört wird.

Eine komplexere Smart-Pointer-Richtlinie beinhaltet das Zählen des Zeigers. Dadurch kann der Zeiger kopiert werden. Wenn die letzte "Referenz" zum Objekt zerstört ist, wird das Objekt gelöscht. Diese Richtlinie wird von implementiert boost::shared_ptr und std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Gezählte Verweiszeiger sind sehr nützlich, wenn die Lebensdauer Ihres Objekts viel komplizierter ist und nicht direkt an einen bestimmten Codeabschnitt oder an ein anderes Objekt gebunden ist.

Es gibt einen Nachteil, gezählte Zeiger zu referenzieren - die Möglichkeit, eine hängende Referenz zu erzeugen:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Eine weitere Möglichkeit ist das Erstellen von Zirkelverweisen:

struct Owner {
   boost::shared_ptr<Owner> other;
};

boost::shared_ptr<Owner> p1 (new Owner());
boost::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Um dieses Problem zu umgehen, haben Boost und C ++ 11 eine definiert weak_ptr einen schwachen (ungezählten) Verweis auf a definieren shared_ptr.


AKTUALISIEREN

Diese Antwort ist ziemlich alt und beschreibt so, was zu der Zeit "gut" war, nämlich die von der Boost-Bibliothek bereitgestellten intelligenten Zeiger. Seit C ++ 11 hat die Standardbibliothek genügend intelligente Zeigertypen zur Verfügung gestellt, weshalb Sie die Verwendung von. Bevorzugen sollten std::unique_ptr, std::shared_ptr und std::weak_ptr.

Es gibt auch std::auto_ptr. Es ist sehr ähnlich wie ein Bereichszeiger, außer dass es auch die "spezielle" gefährliche Fähigkeit hat, kopiert zu werden - die auch unerwartet Besitz überträgt! Es ist in den neuesten Standards veraltet, also sollten Sie es nicht verwenden. Benutze die std::unique_ptr stattdessen.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

1640
2017-09-20 00:48



Hier ist eine einfache Antwort für diese Tage von modernem C ++:

  • Was ist ein intelligenter Zeiger? 
    Es ist eine Art von Wert, der wie ein Zeiger verwendet werden kann, bietet aber die zusätzliche Funktion der automatischen Speicherverwaltung: Wenn der Zeiger nicht mehr verwendet wird, wird der Speicher, auf den er zeigt, freigegeben (siehe auch) die detailliertere Definition auf Wikipedia).
  • Wann sollte ich einen verwenden? 
    In einem Code, der das Verfolgen des Besitzes eines Stücks Speicher beinhaltet, Zuweisen oder Entfernen von Zuweisungen; Der intelligente Zeiger erspart Ihnen oft die Notwendigkeit, diese Dinge explizit zu tun.
  • Aber welcher intelligente Zeiger sollte ich in welchen Fällen verwenden?
    • Benutzen std::unique_ptr wenn Sie nicht beabsichtigen, mehrere Referenzen auf dasselbe Objekt zu halten. Zum Beispiel, verwenden Sie es für einen Zeiger auf den Speicher, der bei der Eingabe eines Bereichs zugeordnet und beim Verlassen des Bereichs freigegeben wird.
    • Benutzen std::shared_ptr wenn Sie von mehreren Orten aus auf Ihr Objekt verweisen möchten und es nicht freigegeben werden soll, bis alle diese Referenzen selbst gelöscht sind.
    • Benutzen std::weak_ptr wenn Sie auf Ihr Objekt von mehreren Stellen aus verweisen möchten - auf diejenigen Referenzen, für die es in Ordnung ist, sie zu ignorieren und aufzuheben (so merken sie nur, dass das Objekt verschwunden ist, wenn Sie versuchen, die Dereferenzierung durchzuführen).
    • Benutze nicht die boost:: intelligente Zeiger oder std::auto_ptr außer in besonderen Fällen, die Sie lesen können, wenn Sie müssen.
  • Hey, ich habe nicht gefragt, welchen man benutzen soll! 
    Ah, aber du wolltest wirklich, gib es zu.
  • Wann sollte ich also normale Zeiger verwenden? 
    Meistens in Code, der Gedächtnisbesitz nicht beachtet. Dies würde typischerweise in Funktionen geschehen, die einen Zeiger von einer anderen Stelle erhalten und keine Kopie des Zeigers zuordnen, freigeben oder speichern, die ihre Ausführung überdauert.

170
2018-05-09 19:06



Intelligenter Zeiger ist ein zeigerartiger Typ mit einigen zusätzlichen Funktionen, z. automatische Speicherfreigabe, Referenzzählung usw.

Kleines Intro ist auf der Seite verfügbar Smart Pointer - Was, warum, was?.

Einer der einfachen Smart-Pointer-Typen ist std::auto_ptr (Kapitel 20.4.5 des C ++ - Standards), das es ermöglicht, Speicher automatisch zu löschen, wenn er außerhalb des Gültigkeitsbereichs liegt und der robuster ist als die Verwendung einfacher Zeiger, wenn Ausnahmen ausgelöst werden, obwohl sie weniger flexibel sind.

Eine andere bequeme Art ist boost::shared_ptr das implementiert Referenzzählung und automatisch die Zuordnung von Speicher, wenn keine Verweise auf das Objekt verbleiben. Dies hilft, Speicherlecks zu vermeiden und ist einfach zu implementieren RAII.

Das Thema wird im Buch ausführlich behandelt "C ++ Templates: The Complete Guide" von David Vandevoorde, Nicolai M. Josuttis, Kapitel Kapitel 20. Smart Pointer. Einige Themen behandelt:


96
2017-09-20 00:32



Definitionen von Chris, Sergdev und Llyod sind korrekt. Ich bevorzuge jedoch eine einfachere Definition, nur um mein Leben einfach zu halten: Ein intelligenter Zeiger ist einfach eine Klasse, die die ->und * Betreiber. Das bedeutet, dass Ihr Objekt semantisch wie ein Zeiger aussieht, aber Sie können es viel cooler Dinge tun, einschließlich Referenzzählung, automatische Zerstörung usw. shared_ptr und auto_ptr sind in den meisten Fällen ausreichend, kommen aber mit ihren eigenen kleinen Eigenheiten einher.


33
2017-09-20 01:53



Ein intelligenter Zeiger ist wie ein normaler (getippter) Zeiger, wie "char *", außer wenn der Zeiger selbst außerhalb des Gültigkeitsbereichs liegt, wird auch dessen Inhalt gelöscht. Sie können es wie einen normalen Zeiger verwenden, indem Sie "->" verwenden, aber nicht, wenn Sie einen tatsächlichen Zeiger auf die Daten benötigen. Dafür können Sie "& * ptr" verwenden.

Es ist nützlich für:

  • Objekte, die neu zugeordnet werden müssen, die aber dieselbe Lebensdauer haben sollen wie etwas auf diesem Stapel. Wenn das Objekt einem intelligenten Zeiger zugewiesen ist, werden sie gelöscht, wenn das Programm diese Funktion / diesen Block verlässt.

  • Datenmitglieder von Klassen, so dass beim Löschen des Objekts alle eigenen Daten gelöscht werden, ohne speziellen Code im Destruktor (Sie müssen sicher sein, dass der Destruktor virtuell ist, was fast immer gut ist) .

Du darfst nicht möchte einen intelligenten Zeiger verwenden, wenn:

  • ... der Zeiger sollte eigentlich nicht die Daten besitzen ... d. h., wenn Sie nur die Daten verwenden, aber Sie wollen, dass sie die Funktion überleben, auf die Sie sie verweisen.
  • ... der intelligente Zeiger wird nicht irgendwann selbst zerstört werden. Sie möchten nicht, dass sie im Speicher abgelegt wird, der niemals zerstört wird (z. B. in einem Objekt, das dynamisch zugewiesen wird, aber nicht explizit gelöscht wird).
  • ... zwei intelligente Zeiger könnten auf dieselben Daten zeigen. (Es gibt jedoch noch intelligentere Zeiger, die damit umgehen ... das heißt Referenzzählung.)

Siehe auch:


26
2017-09-20 00:13



Die meisten Arten von intelligenten Zeigern behandeln die Entsorgung des pointer-to-Objekts für Sie. Es ist sehr praktisch, weil Sie nicht mehr über die manuelle Entsorgung von Objekten nachdenken müssen.

Die am häufigsten verwendeten Smartpointer sind std::tr1::shared_ptr (oder boost::shared_ptr), und seltener std::auto_ptr. Ich empfehle den regelmäßigen Gebrauch von shared_ptr.

shared_ptr ist sehr vielseitig und behandelt eine große Vielfalt von Entsorgungsszenarien, einschließlich Fällen, in denen Objekte "über DLL-Grenzen hinweg" weitergegeben werden müssen (der übliche Albtraumfall, falls dieser anders ist libcs werden zwischen Ihrem Code und den DLLs verwendet).


14
2017-09-20 00:14



Ein intelligenter Zeiger ist ein Objekt, das wie ein Zeiger wirkt, aber zusätzlich Kontrolle über Konstruktion, Zerstörung, Kopieren, Verschieben und Dereferenzieren bietet.

Man kann seinen eigenen intelligenten Zeiger implementieren, aber viele Bibliotheken stellen auch intelligente Zeigerimplementierungen bereit, die jeweils verschiedene Vor- und Nachteile haben.

Beispielsweise, Boost stellt die folgenden Smart-Pointer-Implementierungen bereit:

  • shared_ptr<T> ist ein Zeiger auf T Verwenden einer Referenzzählung, um festzustellen, wann das Objekt nicht mehr benötigt wird.
  • scoped_ptr<T> wird ein Zeiger automatisch gelöscht, wenn er den Gültigkeitsbereich verlässt. Keine Zuordnung ist möglich.
  • intrusive_ptr<T>ist ein weiterer Referenzzähler. Es bietet eine bessere Leistung als shared_ptr, erfordert aber den Typ T einen eigenen Referenzzählmechanismus bereitstellen.
  • weak_ptr<T> ist ein schwacher Zeiger, der mit shared_ptr um Zirkelbezüge zu vermeiden.
  • shared_array<T> ist wie shared_ptr, aber für Arrays von T.
  • scoped_array<T> ist wie scoped_ptr, aber für Arrays von T.

Dies sind nur eine lineare Beschreibungen von jedem und kann nach Bedarf verwendet werden, für weitere Details und Beispiele kann man die Dokumentation von Boost betrachten.

Darüber hinaus stellt die C ++ - Standardbibliothek drei intelligente Zeiger bereit. std::unique_ptr für einzigartiges Eigentum, std::shared_ptr für gemeinsames Eigentum und std::weak_ptr. std::auto_ptr existiert in C ++ 03, ist jetzt aber veraltet.


14
2018-03-12 09:51



Hier ist der Link für ähnliche Antworten: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Ein intelligenter Zeiger ist ein Objekt, das wie ein normaler Zeiger wirkt, aussieht und sich anfühlt, aber mehr Funktionalität bietet. In C ++ werden intelligente Zeiger als Vorlagenklassen implementiert, die einen Zeiger kapseln und Standardzeigeroperatoren außer Kraft setzen. Sie haben eine Reihe von Vorteilen gegenüber regulären Zeigern. Sie werden garantiert als NULL-Zeiger oder als Zeiger auf ein Heap-Objekt initialisiert. Die Indirektion durch einen Nullzeiger wird überprüft. Kein Löschen ist jemals notwendig. Objekte werden automatisch freigegeben, wenn der letzte Zeiger auf sie verschwunden ist. Ein bedeutendes Problem mit diesen intelligenten Zeigern besteht darin, dass sie im Gegensatz zu regulären Zeigern die Vererbung nicht respektieren. Intelligente Zeiger sind für polymorphen Code unattraktiv. Im Folgenden finden Sie ein Beispiel für die Implementierung von Smartpointern.

Beispiel: 

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Diese Klasse implementiert einen intelligenten Zeiger auf ein Objekt vom Typ X. Das Objekt selbst befindet sich auf dem Heap. Hier ist, wie man es benutzt:

smart_pointer <employee> p= employee("Harris",1333);

Wie andere überladene Operatoren verhält sich p wie ein normaler Zeiger,

cout<<*p;
p->raise_salary(0.5);

9
2018-03-07 09:03



http://en.wikipedia.org/wiki/Smart_pointer

In der Informatik ein intelligenter Zeiger   ist ein abstrakter Datentyp, der   simuliert einen Zeiger beim Bereitstellen   zusätzliche Funktionen, z. B. automatisch   Garbage Collection oder Grenzprüfung.   Diese zusätzlichen Funktionen sind vorgesehen   um Fehler zu reduzieren, die durch den Missbrauch von   Zeiger unter Beibehaltung der Effizienz.   In der Regel werden Smartpoints überwacht   die Objekte, die auf sie für die zeigen   Zweck der Speicherverwaltung. Das   Der Missbrauch von Zeigern ist eine Hauptquelle   von Bugs: die konstante Zuordnung,   Freigabe und Referenzierung muss dies   von einem Programm geschrieben werden   die Verwendung von Zeigern macht es sehr wahrscheinlich   dass einige Speicherlecks auftreten.   Intelligente Zeiger versuchen Speicher zu verhindern   Lecks durch die Bereitstellung der Ressource   Freigabe automatisch: wenn der   Zeiger auf ein Objekt (oder das letzte in einem   Reihe von Zeigern) wird zerstört, z   Beispiel, weil es den Rahmen sprengt,   das spitze Objekt ist auch zerstört.


8
2017-09-20 00:12



Sei T eine Klasse in diesem Tutorial Zeiger in C ++ können in 3 Typen unterteilt werden:

1) Rohe Zeiger :

T a;  
T * _ptr = &a; 

Sie halten eine Speicheradresse an einen Ort im Speicher. Verwenden Sie mit Vorsicht, da Programme komplex werden schwer zu verfolgen.

Zeiger mit const Daten oder Adresse {Rückwärts lesen}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Zeiger auf einen Datentyp T, der eine Konstante ist. Das bedeutet, dass Sie den Datentyp nicht mit dem Zeiger ändern können. dh *ptr1 = 19 ; wird nicht funktionieren. Aber Sie können den Zeiger bewegen. dh ptr1++ , ptr1-- ; usw. wird funktionieren. Rückwärts gelesen: Zeiger auf Typ T, der const ist

  T * const ptr2 ;

Ein Const-Zeiger auf einen Datentyp T. Das bedeutet, dass Sie den Zeiger nicht verschieben können, aber Sie können den Wert ändern, auf den der Zeiger zeigt. dh *ptr2 = 19 wird aber funktionieren ptr2++ ; ptr2-- usw. wird nicht funktionieren. Rückwärts lesen: const Zeiger auf einen Typ T

const T * const ptr3 ; 

Ein const-Zeiger auf einen const-Datentyp T. Das bedeutet, dass Sie den Zeiger weder verschieben noch den Datentypzeiger als Zeiger festlegen können. dh. ptr3-- ; ptr3++ ; *ptr3 = 19; wird nicht funktionieren

3) Intelligente Zeiger : { #include <memory> }

Gemeinsamer Zeiger:

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

Implementiert mit Referenzzählung, um zu verfolgen, wie viele "Dinge" auf das Objekt zeigen, auf das der Zeiger zeigt. Wenn dieser Wert auf 0 gesetzt wird, wird das Objekt automatisch gelöscht, dh object wird gelöscht, wenn alle share_ptr, die auf das Objekt verweisen, den Gültigkeitsbereich verlassen. Dies beseitigt die Kopfschmerzen, Objekte löschen zu müssen, die Sie mit new zugewiesen haben.

Schwacher Zeiger:      Hilft bei zyklischen Verweisen, die bei Verwendung von Shared Pointer auftreten     Wenn zwei Objekte auf zwei freigegebene Zeiger zeigen und ein interner gemeinsamer Zeiger auf den jeweils anderen gemeinsamen Zeiger zeigt, wird ein zyklischer Verweis vorhanden sein, und das Objekt wird nicht gelöscht, wenn gemeinsame Zeiger den Gültigkeitsbereich verlassen. Um dies zu lösen, ändern Sie das interne Member von einem shared_ptr zu weak_ptr. Hinweis: Um auf das Element zuzugreifen, auf das durch einen schwachen Zeiger verwiesen wird, verwenden Sie lock (), dies gibt ein weak_ptr zurück.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Sehen : Wann ist std :: weak_ptr nützlich?

Eindeutiger Zeiger:      Leichter intelligenter Zeiger mit exklusivem Besitz. Verwenden Sie, wenn der Zeiger auf eindeutige Objekte zeigt, ohne die Objekte zwischen den Zeigern zu teilen.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Verwenden Sie die Bewegungssemantik, um das Objekt zu ändern, auf das das eindeutige ptr verweist

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Verweise :     Sie können im wesentlichen als const-Zeiger sein, dh als Zeiger, der const ist und nicht mit besserer Syntax verschoben werden kann.

Sehen : Was sind die Unterschiede zwischen einer Zeigervariablen und einer Referenzvariablen in C ++? 

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Referenz : https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ  Danke an Andre für das Aufzeigen dieser Frage.


3
2018-03-03 00:58