2013-04-22 11 views
7

So weit wie ich verstehe, wenn stuff pushed_back in einen Vektor ist, muss es manchmal einen neuen Speicherblock zuweisen, was dazu führt, dass alle Elemente aus dem alten Speicherblock hinein kopiert werden und ihre Destruktoren aufgerufen werden. Da unique_ptr-Destruktoren den eigenen Speicher löschen, wie ist es möglich, dass sie mit Vektor arbeiten? Ist es sicher, unique_ptr in Vektoren zu verwenden? Ist es langsamer als normale Zeiger?vector <unique_ptr> resizing mit push_back - wie funktioniert es?

Antwort

12

was dazu führt, dass alle Elemente aus dem alten Speicherblock in diese kopiert werden und ihre Destruktoren aufgerufen werden. Da unique_ptr-Destruktoren den eigenen Speicher löschen, wie ist es möglich, dass sie mit Vektor arbeiten?

In der Tat, es ist nicht streng Kopieren die Elemente nicht mehr, ist es bewegt. Für Typen, die keinen impliziten oder expliziten Move-Konstruktor haben, ist das gleich. Aber für unique_ptr s bedeutet das, dass neue unique_ptr s in dem neu zugewiesenen Speicher konstruiert werden, wobei ein rvalue-Verweis auf das "alte" unique_ptr s gegeben wird. Ihr Move-Konstruktor macht das Richtige, d. H. Er überträgt das Eigentum von dem alten auf das neue unique_ptrs, wobei die alten leer gelassen werden, so dass nichts gelöscht wird, wenn sie zerstört werden.

Ist es sicher, unique_ptr in Vektoren zu verwenden?

Es ist sparen unique_ptr s verwenden überall, so lange wie Sie Sprachregeln respektieren und "C++ common sense". Das heißt, Sie müssen explizit dumme Dinge zu brechen unique_ptr s sicheres Verhalten. Unter diesen sind z.B.

unique_ptr<T> ptr1 {new T()}; 
unique_ptr<T> ptr2 {ptr1.get()}; //two unique_ptr's owning the same object... 

oder einige destruktiven Handlungen beteiligt reinterpret_cast, memcpy, memset oder andere Dinge, die nicht respektieren Objekt Lebensdauer ++ C: zu geben, das Eigentum an dem Objekt im Besitz einer weiteren intelligenten Zeiger vorgibt.

Ist es langsamer als normale Zeiger?

Vielleicht. Beim Verschieben eines unique_ptr im Vergleich zum Kopieren eines rohen Zeigers, nämlich dem Setzen des Originals auf Null, ist offensichtlich ein kleiner Aufwand verbunden. Aber ob dieser Overhead optimiert werden kann oder nicht, hängt von Ihrem Compiler und Optimierer ab.Und wie immer mit Leistung, konsultieren Sie Ihren Profiler, um zu beurteilen, ob langsamer ist und ob die Verlangsamung von Bedeutung ist. Ich wette, es wird nicht, und unter Berücksichtigung der Menge an Sicherheit, die die intelligenten Zeiger Ihnen geben werden, fragen Sie nie nach unique_ptr 's Leistung.

Hinweis: Wenn Sie die Größe Ihres Vektors im Voraus kennen, denken Sie daran, vector::reserve() zu verwenden. Es speichert Sie die Umverteilungen und Bewegungen der unique_ptr s. Und wenn Sie nur die ungefähre Größe wissen, die Ihr Vektor haben wird, seien Sie nicht kleinlich - unique_ptr s sind nicht sehr groß (normalerweise so groß wie ein roher Zeiger plus der Deleter, der möglicherweise weg optimiert wird), also reserviert a Wenige Prozent mehr werden nicht weh tun, es sei denn, Sie haben wirklich enge Speicherbeschränkungen.

+0

* so wird das Reservieren von hundert mehr nicht schaden, es sei denn, Sie haben wirklich enge Speicherbeschränkungen. * => Nun, da Container für ein Dutzend oder so Elemente am häufigsten verwendet werden, würde ich es bevorzugen, eine Faustregel als Prozentsatz anzugeben ; wie 10% mehr. –

+0

@MatthieuM. Danke für die Rückmeldung, ich habe diesen Teil neu formuliert. –

+0

@Arne: Wenn wir unique_ptr <> in Vektor <> Container verwenden können, warum nicht auto_ptr <>? Afterall auto_ptr <> verschiebt auch die Verantwortung des Objekts auf das neue Objekt. Also sollte auto_ptr <> auch in diesem Sinne sicher sein. Aber ich glaube das ist nicht der Fall? – David

3

Nach cppreference ist einer der Anwendungsfälle für std::unique_ptr Verwendung in "Move-Aware-Container" wie std::vector. Dies bedeutet, dass std::vector<T> intelligent genug ist, um zu erkennen, wenn T beweglich ist, was für std::unique_ptr der Fall ist, und den Move-Konstruktor zu verwenden, wenn die Größe des Vektors geändert wird.

6

Nun mit Umzug Semantik ist es möglich, eine unique_ptr von einem Ort zu einem anderen zu verschieben. Dies vermeidet die Zerstörung der Daten, die der Zeiger enthält, wenn er mit std::move von einem Speicherort zu einem anderen "verschoben" wird.

Es ist eine Art, flache Kopien vom alten Vektor-Array an den neuen Speicherort durchzuführen, wenn der Vektor wächst.

+0

@RandyGual AfterAutle auto_ptr <> unterstützen auch sementic, überträgt es die Verantwortung des Objekts auf das neue Objekt. Also sollte auto_ptr <> auch in diesem Sinne sicher sein. Aber ich glaube das ist nicht der Fall? – David

Verwandte Themen