Wahl zwischen vector::resize() und vector::reserve()

Lesezeit: 7 Minuten

Wahl zwischen vectorresize und vectorreserve
iammilind

Ich weise meinem a vorab etwas Speicher zu vector Mitgliedsvariable. Der folgende Code ist ein minimaler Teil

class A {
  vector<string> t_Names;
public:
  A () : t_Names(1000) {}
};

Nun irgendwann, wenn die t_Names.size() gleich 1000. Ich beabsichtige, die Größe um zu erhöhen 100. Wenn es dann reicht 1100wieder erhöhen um 100 und so weiter.

Meine Frage ist, zwischen was ich mich entscheiden soll vector::resize() und vector::reserve(). Gibt es in einem solchen Szenario eine bessere Wahl?

Bearbeiten: Ich habe eine Art genaue Schätzung für die t_Names. Ich schätze, es wird ungefähr sein 700 zu 800. Allerdings drin sicher (selten) Situationen, kann es mehr als wachsen 1000.

  • Sie erkennen, dass dies bedeutet, dass es kein Vektorwachstum mehr gibt amortisierte konstante Zeit und Sie verlieren einen der Leistungsvorteile der Verwendung std::vector.

    – Hochofen

    13. September 2011 um 7:37 Uhr

  • Verwandte, siehe C++ einfacher gemacht: Wie Vektoren wachsen auf der Website von Dr. Dobbs.

    – jww

    22. Dezember 2016 um 5:21 Uhr

Wahl zwischen vectorresize und vectorreserve
Jan Hudec

Die beiden Funktionen machen sehr unterschiedliche Dinge!

Die resize() -Methode (und das Übergeben des Arguments an den Konstruktor ist äquivalent dazu) fügt die entsprechende Anzahl von Elementen in den Vektor ein oder löscht sie, um ihm die angegebene Größe zu geben (es hat ein optionales zweites Argument, um ihren Wert anzugeben). Es wird die beeinflussen size()wird die Iteration alle diese Elemente durchlaufen, push_back wird nach ihnen eingefügt und Sie können mit direkt darauf zugreifen operator[].

Die reserve() -Methode weist nur Speicher zu, lässt ihn jedoch nicht initialisiert. Es wirkt nur capacity()aber size() wird unverändert bleiben. Die Objekte haben keinen Wert, da dem Vektor nichts hinzugefügt wird. Wenn Sie die Elemente dann einfügen, wird keine Neuzuordnung stattfinden, da dies im Voraus geschehen ist, aber das ist der einzige Effekt.

Es kommt also darauf an, was Sie wollen. Wenn Sie ein Array von 1000 Standardelementen wünschen, verwenden Sie resize(). Wenn Sie ein Array wünschen, in das Sie 1000 Elemente einfügen möchten, und einige Zuordnungen vermeiden möchten, verwenden Sie reserve().

BEARBEITEN: Der Kommentar von Blastfurnace veranlasste mich, die Frage erneut zu lesen und zu erkennen, dass in Ihrem Fall die richtige Antwort lautet nicht vorbelegen manuell. Fügen Sie einfach die Elemente am Ende nach Bedarf ein. Der Vektor wird nach Bedarf automatisch neu zugewiesen und wird dies tun mehr effizienter als der erwähnte manuelle Weg. Der einzige Fall, wo reserve() Sinnvoll ist es, wenn Sie eine einigermaßen genaue Schätzung der Gesamtgröße haben, die Sie im Voraus benötigen.

EDIT2: Bearbeiten der Anzeigenfrage: Wenn Sie eine erste Schätzung haben, dann reserve() diese Schätzung. Wenn sich herausstellt, dass es nicht genug ist, lassen Sie einfach den Vektor sein Ding machen.

  • “Der einzige Fall, in dem reserve() sinnvoll ist, ist, wenn Sie eine einigermaßen genaue Schätzung der Gesamtgröße haben, die Sie im Voraus benötigen.” – nicht ganz richtig, seit Anruf reserve() Sie selbst zu bestimmten Zeiten können Ihnen manchmal helfen, alle Zeiger oder Iteratoren zu verwalten, die Sie für Elemente des Vektors haben (und insbesondere, dass sie durch Neuzuweisung ungültig gemacht werden). Nicht, dass diese Frage irgendwelche Anzeichen dafür enthält, dass solche Dinge vor sich gehen. Und es stimmt, dass Sie eine Obergrenze dafür kennen müssen, wie viele Elemente Sie während der Zeit hinzufügen, in der Ihre Zeiger/Iteratoren benötigt werden.

    – Steve Jessop

    13. September 2011 um 9:20 Uhr


  • @Jan: Nun, es ist zerbrechlich oder nicht, je nachdem, wie schwierig Sie es sich selbst gemacht haben, das erforderliche Eigentum zu erhalten. Etwas wie x.reserve(x.size() + newdata); vector<int>::iterator special_element = get_special_element(x); for (int i = 0; i < newdata; ++i) { if some_function(i, special_element) x.push_back(i); } ist ziemlich robust, was die Platzreservierung betrifft. Ich habe keine Ahnung, wie viele Elemente tatsächlich hinzugefügt werden, aber ich habe eine Obergrenze. Natürlich kann man bei Vektoren im Zweifelsfall einfach Indizes statt Iteratoren verwenden, der Unterschied ist meist vernachlässigbar.

    – Steve Jessop

    13. September 2011 um 9:33 Uhr

  • Ihre Formulierung ist für jemanden, der die richtige Antwort bereits kennt, sinnvoll, könnte aber Personen, die die Frage stellen müssen, leicht in die Irre führen. “resize()…fügt die angegebene Anzahl von Elementen in den Vektor ein” – nur wahr, wenn es zum ersten Mal verwendet wird – es fügt im Allgemeinen die Differenz zwischen der angeforderten Anzahl und der bereits vorhandenen ein size(). “Die Methode reserve () weist nur Speicher zu” – sie kann Speicher zuordnen oder nicht, je nachdem, ob capacity() bereits ausreichend ist, müssen möglicherweise auch Elemente verschoben und ihr ursprünglicher Speicher freigegeben werden. “möchte ein paar Zuordnungen vermeiden” und Kopien etc

    – Toni Delroy

    28. Dezember 2011 um 8:46 Uhr

  • Tatsächlich ist das Reservieren vor dem Schieben lebenswichtig und muss verwendet werden. Angenommen, Sie codieren eine Art 3D-Modelllader und das Modell hat etwa 15000 Scheitelpunkte. Wenn Sie versuchen, jeden Scheitelpunkt während des Ladens zu push_backen, ohne ihn vorher vorab zuzuweisen, wird dies viel Zeit in Anspruch nehmen. Ich habe das persönlich erlebt, ich habe versucht, ein Auto-OBJ-Modell mit fast 100000 Scheitelpunkten zu laden. Es dauerte 30 Sekunden. Dann habe ich den Code mithilfe der Vorabzuweisung mit .reserve() umgestaltet, jetzt dauert es 3 Sekunden. Nur ein .reserve(100000) am Anfang des Codes einzufügen, sparte 27 Sekunden.

    – deniz

    12. Oktober 2013 um 7:25 Uhr


  • @deniz Das ist auf der Skala von 100000 trivial, aber auf der Skala von 100 bis 300 nicht wahr, wo das Reservieren verschwenderisch sein kann, wenn es unnötig gemacht wird.

    – deworde

    21. März 2017 um 10:20 Uhr

Wahl zwischen vectorresize und vectorreserve
Nawaz

resize() weist nicht nur Speicher zu, sondern auch schafft so viele Instanzen wie die gewünscht Größe, an die Sie übergeben resize() als argument. Aber reserve() weist nur Speicher zu, erstellt keine Instanzen. Das ist,

std::vector<int> v1;
v1.resize(1000); //allocation + instance creation
cout <<(v1.size() == 1000)<< endl;   //prints 1
cout <<(v1.capacity()==1000)<< endl; //prints 1

std::vector<int> v2;
v2.reserve(1000); //only allocation
cout <<(v2.size() == 1000)<< endl;   //prints 0
cout <<(v2.capacity()==1000)<< endl; //prints 1

Ausgabe (Online-Demo):

1
1
0
1

Damit resize() ist möglicherweise nicht wünschenswert, wenn Sie die standardmäßig erstellten Objekte nicht möchten. Langsam wird es auch. Außerdem, wenn Sie push_back() neue Elemente dazu, die size() des Vektors wird weiter zunehmen durch Zuweisung von neuem Speicher (was auch bedeutet, dass die vorhandenen Elemente in den neu zugewiesenen Speicherplatz verschoben werden). Wenn Sie verwendet haben reserve() zu Beginn, um sicherzustellen, dass bereits genügend zugewiesener Speicher vorhanden ist, die size() des Vektors wird zunehmen, wenn Sie push_back() dazu, aber es wird nicht wieder neuen Speicher zuweisen, bis der Speicherplatz, den Sie dafür reserviert haben, aufgebraucht ist.

  • Nachdem reserve(N)wir können benutzen operator [] harmlos. Korrekt ?

    – iammilind

    13. September 2011 um 8:48 Uhr

  • Während die meisten Implementierungen den genauen Betrag zuweisen, den Sie anfordern reserveerfordert die Spezifikation nur, dass mindestens so viel zugewiesen wird, sodass einige Implementierungen möglicherweise auf eine bestimmte Grenze aufrunden und somit eine höhere Kapazität als 1000 aufweisen.

    – Jan Hudec

    13. September 2011 um 8:49 Uhr

  • @iammilind: Nein, wenn der Index größer oder gleich ist v.size(). Beachten Sie, dass reserve(N) ändert sich nicht size() des Vektors.

    – Nawaz

    13. September 2011 um 8:51 Uhr

  • @iammilind: FALSCH. Nach dem Aufruf von reSERVE werden keine Einträge hinzugefügt, sondern nur genügend Speicher zum Hinzufügen erhalten.

    – Jan Hudec

    13. September 2011 um 8:51 Uhr


Aus Ihrer Beschreibung geht hervor, dass Sie den zugewiesenen Speicherplatz des Vektors t_Names “reservieren” möchten.

Beachten Sie das resize Initialisieren Sie den neu zugewiesenen Vektor wo reserve ordnet nur zu, baut aber nicht. Daher ist “Reserve”. viel schneller als “Größe ändern”

Informationen zum Unterschied finden Sie in der Dokumentation Größe ändern und Reservieren

  • Bitte beziehen Sie sich stattdessen hier: Vektor und Kapazität (warum?)

    – sehen

    13. September 2011 um 8:06 Uhr


  • Danke für die Ergänzung des Links, siehe

    – eintauchen

    13. September 2011 um 8:58 Uhr

reserviert, wenn Sie nicht möchten, dass die Objekte beim Reservieren initialisiert werden. außerdem ziehen Sie es vielleicht vor, die Anzahl logisch zu unterscheiden und zu verfolgen, wenn Sie die Größe ändern. Daher gibt es einen Verhaltensunterschied in der Schnittstelle – der Vektor stellt die gleiche Anzahl von Elementen dar, wenn er reserviert ist, und wird 100 Elemente größer, wenn er in Ihrem Szenario skaliert wird.

Gibt es in einem solchen Szenario eine bessere Wahl?

es hängt ganz von Ihren Zielen ab, wenn Sie das Standardverhalten bekämpfen. Einige Leute werden angepasste Allokatoren bevorzugen – aber wir brauchen wirklich eine bessere Vorstellung davon, was Sie in Ihrem Programm zu lösen versuchen, um Sie gut beraten zu können.

fwiw, viele Vektorimplementierungen verdoppeln einfach die Anzahl der zugewiesenen Elemente, wenn sie wachsen müssen. Versuchen Sie, die Spitzenzuweisungsgrößen zu minimieren, oder versuchen Sie, genügend Speicherplatz für ein lockfreies Programm oder etwas anderes zu reservieren?

995480cookie-checkWahl zwischen vector::resize() und vector::reserve()

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy