Es ist ein Thread in den Kommentaren in diesem Beitrag über die Verwendung von std::vector::reserve()
vs. std::vector::resize()
.
Hier ist der Originalcode:
void MyClass::my_method()
{
my_member.reserve(n_dim);
for(int k = 0 ; k < n_dim ; k++ )
my_member[k] = k ;
}
Ich glaube, um Elemente in das zu schreiben vector
, ist es richtig, anzurufen std::vector::resize()
, nicht std::vector::reserve()
.
Tatsächlich "stürzt" der folgende Testcode in Debug-Builds in VS2010 SP1 ab:
#include <vector>
using namespace std;
int main()
{
vector<int> v;
v.reserve(10);
v[5] = 2;
return 0;
}
Habe ich recht oder irre ich mich? Und ist VS2010 SP1 richtig oder falsch?
resize()
, und der Zweifel wurde ausgeräumt. An Moderatoren: Sie können diese Frage jederzeit löschen, wenn sie "zu lokalisiert" ist, oder sie behalten, wenn Sie der Meinung sind, dass sie in Zukunft jemand anderem helfen könnte.Antworten:
Es gibt zwei verschiedene Methoden aus einem Grund:
std::vector::reserve
ordnet den Speicher zu, ändert jedoch nicht die Größe Ihres Vektors, der eine logische Größe wie zuvor hat.std::vector::resize
ändert tatsächlich die Größe Ihres Vektors und füllt jeden Raum mit Objekten in ihrem Standardzustand. Wenn sie Ints sind, sind sie alle Null.Nach der Reserve benötigen Sie in Ihrem Fall viele push_backs, um in Element 5 zu schreiben. Wenn Sie dies nicht möchten, sollten Sie in Ihrem Fall die Größenänderung verwenden.
Eine Sache über Reserve: Wenn Sie dann Elemente mit push_back hinzufügen, bleiben alle vorhandenen Referenzen, Iteratoren oder Zeiger auf Daten in Ihrem Vektor gültig, bis Sie die von Ihnen reservierte Kapazität erreicht haben. Wenn ich also 1000 reserviere und meine Größe 5 ist,
&vec[4]
bleibt die gleiche, bis der Vektor 1000 Elemente hat. Danach kann ich aufrufenpush_back()
und es wird funktionieren, aber der gespeicherte Zeiger von&vec[4]
früher ist möglicherweise nicht mehr gültig.quelle
std::vector::reserve
das gelegentliche Kopieren des vollständigen Arrays verhindern aufpush_back
?< size()
Container vorhanden sind, ist nicht zulässig. Sie existieren dort nach der Definition der Sprache nicht. Wenn Ihr Compiler beschließt, die Atomwaffen nicht zu starten und stattdessen nur den RAM so anstößt, wie Sie es möchten, ist das einfach viel Glück. Oder Pech, denke ich; Im Idealfall könnten wir alle ungültigen Dinge abfangen, die alle Programmierer tun würden, aber viel Glück, jemals dort anzukommen!Hier beantwortet von Jan Hudec : Wahl zwischen vector :: resize () und vector :: Reserve ()
quelle
Es hängt davon ab, was Sie tun möchten.
reserve
ist nicht fügen Sie alle Elemente dervector
; es ändert nur dascapacity()
, was garantiert, dass das Hinzufügen von Elementen nicht neu zugewiesen wird (und z. B. Iteratoren ungültig macht).resize
fügt sofort Elemente hinzu. Wenn Sie später Elemente hinzufügen möchten (insert()
,push_back()
), verwenden Siereserve
. Wenn Sie später (mit[]
oderat()
) auf Elemente zugreifen möchten , verwenden Sieresize
. DuMyClass::my_method
kannst also entweder sein:void MyClass::my_method() { my_member.clear(); my_member.reserve( n_dim ); for ( int k = 0; k < n_dim; ++ k ) { my_member.push_back( k ); } }
oder
void MyClass::my_method() { my_member.resize( n_dim ); for ( int k = 0; k < n_dim; ++ k ) { my_member[k] = k; } }
Welchen Sie gewählt haben, ist eine Frage des Geschmacks, aber der von Ihnen zitierte Code ist eindeutig falsch.
quelle
Es sollte wahrscheinlich eine Diskussion darüber geben, wann beide Methoden mit einer Zahl aufgerufen werden, die WENIGER als die aktuelle Größe des Vektors ist.
Anrufe
reserve()
mit einer Nummer, die kleiner als die Kapazität ist, haben keinen Einfluss auf die Größe oder die Kapazität.Wenn Sie
resize()
mit einer Nummer anrufen, die kleiner als die aktuelle Größe ist, wird der Container auf diese Größe reduziert, wodurch die überschüssigen Elemente effektiv zerstört werden.Zusammenfassend lässt
resize()
sich sagen, dass Speicher frei wird, während diesreserve()
nicht der Fall ist.quelle
Ja, Sie haben Recht, Luchian hat gerade einen Tippfehler gemacht und ist wahrscheinlich zu kaffeeentzogen, um seinen Fehler zu erkennen.
quelle
Durch Größenänderung wird tatsächlich die Anzahl der Elemente im Vektor geändert. Neue Elemente werden standardmäßig erstellt, wenn durch die Größenänderung der Vektor wächst.
vector<int> v; v.resize(10); auto size = v.size();
In diesem Fall beträgt die Größe 10.
Reserve hingegen fordert nur an, dass der interne Puffer auf die angegebene Größe vergrößert wird, ändert jedoch nicht die "Größe" des Arrays, sondern nur seine Puffergröße.
vector<int> v; v.reserve(10); auto size = v.size();
In diesem Fall ist die Größe immer noch 0.
Um Ihre Frage zu beantworten: Ja, Sie haben Recht, auch wenn Sie genügend Speicherplatz reservieren, greifen Sie mit dem Indexoperator immer noch auf nicht initialisierten Speicher zu. Mit einem int, das nicht so schlecht ist, aber im Fall eines Klassenvektors würden Sie auf Objekte zugreifen, die nicht konstruiert wurden.
Die Überprüfung der Grenzen von Compilern, die auf den Debug-Modus eingestellt sind, kann offensichtlich durch dieses Verhalten verwechselt werden, weshalb möglicherweise der Absturz auftritt.
quelle