2014-09-18 3 views
69

Die cplusplus.com shared_ptr page ruft eine Unterscheidung zwischen einem leerstd::shared_ptr und einem nullshared_ptr. Die cppreference.com page nicht explizit die Unterscheidung, aber verwendet sowohl "leer" und Vergleich zu nullptr in seiner Beschreibung von std::shared_ptr Verhalten.Was ist der Unterschied zwischen einem leeren und einem null std :: shared_ptr in C++?

Gibt es einen Unterschied zwischen einem leeren und einem Null shared_ptr? Gibt es einen Anwendungsfall für solche Zeiger mit gemischtem Verhalten? Ist ein nicht leerer Nullwert shared_ptr überhaupt sinnvoll? Würde es im Normalfall jemals einen Fall geben (d. H. Wenn Sie keinen explizit konstruierten), wo Sie mit einem leeren, aber nicht null shared_ptr enden könnten?

Und ändert sich eine dieser Antworten, wenn Sie die Boost-Version anstelle der C++ 11-Version verwenden?

Antwort

72

Es ist eine seltsame Ecke von shared_ptr Verhalten. Es hat einen Konstruktor, dass Sie eine shared_ptr dass besitzen etwas und Punkte etwas anderes machen kann:

Eigentum
template< class Y > 
shared_ptr(const shared_ptr<Y>& r, T *ptr); 

Die shared_ptr konstruierten mit diesem Konstruktor Aktien mit r, aber Punkten was auch immer ptr verweist auf (dh Aufruf get() oder operator->() wird ptr zurückgeben). Dies ist praktisch für Fälle, in denen ptr auf ein Unterobjekt (z. B. ein Datenelement) des Objekts zeigt, das zu r gehört.

Die gewünschte Seite ein shared_ptr verknüpft Anrufe, die nichts leer und eine shared_ptr, die (das heißt, deren get() == nullptr) verweist auf nichts besitzt null. (Empty wird in diesem Sinne von der Norm verwendet; null ist nicht.) Sie können eine null-aber nicht-leere shared_ptr konstruieren, aber es wird nicht sehr nützlich sein. Ein leerer-aber-nicht-null shared_ptr ist im Wesentlichen ein nicht besitzender Zeiger, der verwendet werden kann, um einige seltsame Dinge wie passing a pointer to something allocated on the stack to a function expecting a shared_ptr zu tun (aber ich würde vorschlagen, wer immer shared_ptr zuerst in die API eingibt).

boost::shared_ptr auch has this constructor, die sie die Aliasing Konstruktor nennen.

+7

Bemerkenswert: ** C++ 11 § 20.7.2.2.1 (p16) ** "Hinweis: Dieser Konstruktor erlaubt die Erstellung einer leeren 'shared_ptr'-Instanz mit einem nicht-NULL gespeicherten Zeiger." Erwähnenswert ist auch der vorhergehende Hinweis (S. 15), "Um die Möglichkeit eines Dangling-Pointers zu vermeiden, muss der Benutzer dieses Konstruktors sicherstellen, dass' p' mindestens so lange gültig bleibt, bis die Eigentümergruppe von 'r' zerstört ist." Eine selten genutzte Konstruktion. – WhozCraig

+0

@Cubbi Ein 'shared_ptr', dessen' get() '' 'nullptr' * zurückgibt, vergleicht * gleich mit' nullptr', unabhängig davon, ob es irgendetwas besitzt. –

+3

Ein null-aber-nicht-leeres 'shared_ptr's * kann * nützlich sein, um sicherzustellen, dass eine Funktion ausgeführt wird, sobald alle Besitzer von Zeigern außerhalb des Gültigkeitsbereichs sind (selbst im Falle einer Ausnahme!). Nicht sicher, ob es jetzt eine spezielle Klasse dafür gibt. – coldfix

2

Gibt es einen Unterschied zwischen einem leeren und einem Null shared_ptr?

Leere shared_ptr verfügt nicht über Steuerblock und seine Verwendung mitgezählt 0. Kopie des leeren shared_ptr ist eine andere leer shared_ptr sein. Sie sind beide getrennt shared_ptr s, die gemeinsame Steuerblock nicht teilen, weil sie es nicht haben. Leer shared_ptr kann mit Standardkonstruktor oder mit Konstruktor erstellt werden, der nullptr übernimmt.

Nicht leer Null shared_ptr hat Steuerblock, der mit anderen shared_ptr s geteilt werden kann.Kopie der nicht leeren Null shared_ptr ist shared_ptr, die den gleichen Steuerblock wie die ursprüngliche shared_ptr teilt, so verwenden Sie zählen ist nicht 0. Es kann gesagt werden, dass alle Kopien von shared_ptr teilen die gleichen nullptr. Nicht leere null shared_ptr kann mit Null-Zeiger des Objekttypen (nicht nullptr)

Hier ist beispielsweise aufgebaut sein:

#include <iostream> 
#include <memory> 

int main() 
{ 
    std::cout << "std::shared_ptr<int> ptr1:" << std::endl; 
    { 
     std::shared_ptr<int> ptr1; 
     std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl; 
     std::shared_ptr<int> ptr2 = ptr1; 
     std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;   
     std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl; 
    } 
    std::cout << std::endl; 

    std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl; 
    { 
     std::shared_ptr<int> ptr1(nullptr); 
     std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl; 
     std::shared_ptr<int> ptr2 = ptr1; 
     std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;   
     std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl; 
    } 
    std::cout << std::endl; 

    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl; 
    { 
     std::shared_ptr<int> ptr1(static_cast<int*>(nullptr)); 
     std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl; 
     std::shared_ptr<int> ptr2 = ptr1; 
     std::cout << "\tuse count after copying ptr: " << ptr1.use_count() << std::endl;   
     std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl; 
    } 
    std::cout << std::endl; 

    return 0; 
} 

Es gibt:

std::shared_ptr<int> ptr1: 
    use count before copying ptr: 0 
    use count after copying ptr: 0 
    ptr1 is null 

std::shared_ptr<int> ptr1(nullptr): 
    use count before copying ptr: 0 
    use count after copying ptr: 0 
    ptr1 is null 

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr)) 
    use count before copying ptr: 1 
    use count after copying ptr: 2 
    ptr1 is null 

http://coliru.stacked-crooked.com/a/54f59730905ed2ff

+0

Ich denke, dies ist die bessere Antwort, warum wir im benutzerdefinierten Deleater von shared_ptr auf Null überprüfen müssen. [Ist es sinnvoll, im benutzerdefinierten Deleater von shared_ptr nach nullptr zu suchen?] (Https://stackoverflow.com/questions/42962515/does-it-make-sense-to-check-for-nullptr-in-custom-deleter -of-shared-ptr/42962962) –