vectorunique_ptr resizing mit push_back - wie geht das?

7

Soweit ich weiß, muss stuff, wenn stuff in einen Vektor zurückgeschoben wird, manchmal einen neuen Speicherblock zuweisen, was dazu führt, dass alle Elemente aus dem alten Speicherblock hineinkopiert 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?

    
Vittorio Romeo 22.04.2013, 06:27
quelle

3 Antworten

12
  

führt dazu, 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?

Tatsächlich ist es nicht das Kopieren der Elemente mehr, es ist Verschieben . Für Typen, die keinen impliziten oder expliziten Move-Konstruktor haben, ist das gleich. Aber für unique_ptr s bedeutet dies, dass neue unique_ptr s in dem neu zugewiesenen Speicher erstellt werden, wenn eine rvalue-Referenz auf die "alte" unique_ptr s gegeben ist. Ihr Move-Konstruktor macht das Richtige, d. H. Er überträgt das Eigentumsrecht vom alten auf das neue unique_ptr s, wobei die alten leer bleiben, so dass nichts gelöscht wird, wenn sie zerstört werden.

  

Ist es sicher, unique_ptr in Vektoren zu verwenden?

Es ist sicher, unique_ptr s überall zu verwenden , solange Sie Sprachregeln und "C ++ common sense" beachten. Das heißt, Sie müssen explizit dumme Dinge tun, um unique_ptr s sicheres Verhalten zu brechen. Unter diesen sind z.B. so tun, als würde man dem eigenen Objekt noch einen weiteren intelligenten Zeiger zuweisen:

%Vor%

oder einige destruktive Aktionen mit reinterpret_cast , memcpy , memset oder anderen Dingen, die die C ++ Objektlebensdauer nicht respektieren.

  

Ist es langsamer als normale Zeiger?

Vielleicht. Beim Verschieben von unique_ptr im Vergleich zum Kopieren eines rohen Zeigers, also 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 der 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 der Leistung von unique_ptr .

Hinweis: Wenn Sie die Größe Ihres Vektors im Voraus kennen, denken Sie daran, vector::reserve() zu verwenden. Es wird dir die Neuzuweisungen und Bewegungen von unique_ptr s ersparen. Und wenn Sie nur die ungefähre Größe kennen, 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) ein paar Prozent mehr zu reservieren, wird nicht schaden, es sei denn, Sie haben wirklich enge Speicherbeschränkungen.

    
Arne Mertz 22.04.2013, 07:24
quelle
6

Nun, mit der Bewegungssemantik ist es möglich, ein 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 Speicherplatz zu einem anderen "verschoben" wird.

Es ist eine Art, flache Kopien vom alten Vektor-Array zum neuen Speicherort zu bringen, wenn der Vektor wächst.

    
RandyGaul 22.04.2013 06:32
quelle
3

Laut cppreference wird einer der Anwendungsfälle für std::unique_ptr in "move- bewusste Container ", wie zum Beispiel std::vector . Dies impliziert, dass std::vector<T> intelligent genug ist, um festzustellen, ob T beweglich ist, was für std::unique_ptr der Fall ist, und den move -Konstruktor bei der Größenänderung des Vektors zu verwenden.

    
user4815162342 22.04.2013 06:31
quelle