2016-12-01 5 views
13

Angenommen, ich den folgenden Code in C++ haben:Führt diese Verwendung von std :: make_unique zu nicht eindeutigen Zeigern?

#include <memory> 
#include <iostream> 

struct Some { 
     Some(int _a) : a(_a) {} 
     int a; 
}; 

int main() { 
     Some some(5); 

     std::unique_ptr<Some> p1 = std::make_unique<Some>(some); 
     std::unique_ptr<Some> p2 = std::make_unique<Some>(some); 

     std::cout << p1->a << " " << p2->a << std::endl; 
     return 0; 
} 

Wie ich verstehe, sind eindeutige Hinweise verwendet, um sicherzustellen, dass Ressourcen nicht gemeinsam genutzt werden. Aber in diesem Fall verweisen sowohl p1 als auch p2 auf dieselbe Instanz some.

Bitte enthüllen Sie die Situation.

+1

Ihre Situation wäre leicht zu diagnostizieren gewesen, wenn Sie die Zeigerwerte selbst anstatt des a-Feldes der Spitzen gedruckt hätten. Oder du hast einen "lauten" Kopierkonstruktor erstellt. Der einfachste Fehler war wahrscheinlich, dass 'make_unique' einen Zeiger auf ein bestimmtes Objekt erzeugt (hier die lokale Variable' some'); das ist nicht das, was es tut oder ist. –

+2

Ich bin völlig erstaunt, dass dieser arme Post so viele Upvotes bekommen hat. Was ist los mit SO? – Walter

Antwort

26

Sie verweisen nicht auf die gleiche Ressource, sie zeigen jeweils auf eine andere Kopie von es. Sie können es veranschaulichen, indem Sie den Copykonstruktor Löschen der Fehler zu sehen:

#include <memory> 
#include <iostream> 

struct Some { 
     Some(int _a) : a(_a) {} 
     Some(Some const&) = delete; 
     int a; 
}; 

int main() { 
     Some some(5); 

     std::unique_ptr<Some> p1 = std::make_unique<Some>(some); //error here 
     std::unique_ptr<Some> p2 = std::make_unique<Some>(some); 

     std::cout << p1->a << " " << p2->a << std::endl; 
     return 0; 
} 
+4

Es ist jedoch erwähnenswert, dass 'unique_ptr' keine Möglichkeit hat, einzigartige Eigentumsrechte durchzusetzen. Ein unvorsichtiger Programmierer kann leicht den Besitz desselben Objekts zwischen zwei verschiedenen "unique_ptr" teilen, was höchstwahrscheinlich zu Laufzeit zu undefiniertem Verhalten führen wird. – ComicSansMS

+0

@ComicSansMS, Sie sind 100% richtig. Aber ich bin ambivalent über das Hinzufügen eines Beispiels die Shows, wie es getan werden kann ... – StoryTeller

+6

Ich stimme dem zu. Keine Notwendigkeit, den Leuten zu zeigen, wie sie sich die Beine ausblasen können. – ComicSansMS

16

std::make_unique erstellt Objekte, Aufrufkonstruktor mit angegebenen Argumenten.

Sie haben Some& als Parameter übergeben, und hier wurde der Kopierkonstruktor aufgerufen und ein neues Objekt erstellt.

Also, P1 und P2 sind zwei absolut unterschiedliche Zeiger, aber von demselben Objekt aufgebaut, Copykonstruktor mit

1

Um zu testen, ob zwei Zeiger auf das gleiche Objekt Instanz zeigen, sollten Sie die Standorte weisen sie auf, anstelle der Objektelementvariablen vergleichen:

std::cout << &(*p1) << " " << &(*p2) << std::endl; 

die zeigen, dass sie tatsächlich auf der gleichen Instanz nicht Punkt tun.

NACHTRAG: Wie Remy Lebeau wies darauf hin, seit 11 C++ ist es ratsam, die std::addressof Funktion für diesen Zweck zu verwenden, die die tatsächliche Adresse eines Objekts erhält, selbst wenn die & Betreiber überlastet sind:

std::cout << std::addressof(*p1) << " " << std::addressof(*p2) << std::endl; 
+2

Dieser Code würde fehlschlagen, wenn die Klasse einen benutzerdefinierten 'Operator &' implementiert.Das ist, was 'std :: addressof()' eingeführt wurde, um zu lösen: 'std :: cout << std :: Adresse von (* p1) <<" "<< std :: Adresse von (* p2) << std :: endl; ' –

+0

Sie haben Recht, danke. Für das gegebene Beispiel ist es nicht notwendig, aber es ist sicherlich sinnvoll, es trotzdem zu benutzen. Ich habe es der Antwort hinzugefügt. – Meyer

9

both p1 and p2 point to the same instance some

No, they don't.

#include <memory> 
#include <iostream> 

struct Some { 
     Some(int _a) : a(_a) {} 
     int a; 
}; 

int main() { 
     Some some(5); 

     std::unique_ptr<Some> p1 = std::make_unique<Some>(some); 
     std::unique_ptr<Some> p2 = std::make_unique<Some>(some); 

     std::cout << p1->a << " " << p2->a << std::endl; 
     p1->a = 42; 
     std::cout << p1->a << " " << p2->a << std::endl; 
     return 0; 
} 

output:

0.123.
Verwandte Themen