Jest wątek w sekcji komentarzy w tym poście na temat korzystania std::vector::reserve()
Vs. std::vector::resize()
.
Oto oryginalny kod:
void MyClass::my_method()
{
my_member.reserve(n_dim);
for(int k = 0 ; k < n_dim ; k++ )
my_member[k] = k ;
}
Uważam, że aby wpisać elementy w elemencie vector
, właściwą rzeczą jest wywołanie std::vector::resize()
, a nie std::vector::reserve()
.
W rzeczywistości następujący kod testowy „ulega awarii” w kompilacjach debugowania w VS2010 z dodatkiem SP1:
#include <vector>
using namespace std;
int main()
{
vector<int> v;
v.reserve(10);
v[5] = 2;
return 0;
}
Mam rację, czy się mylę? I czy VS2010 SP1 jest poprawny, czy nie?
resize()
, a wątpliwości zostały wyjaśnione. Do moderatorów: możesz usunąć to pytanie, jeśli jest „zbyt zlokalizowane”, lub zachować je, jeśli uważasz, że może pomóc komuś w przyszłości.Odpowiedzi:
Istnieją dwie różne metody z jakiegoś powodu:
std::vector::reserve
przydzieli pamięć, ale nie zmieni rozmiaru wektora, który będzie miał logiczny rozmiar taki sam jak wcześniej.std::vector::resize
faktycznie zmodyfikuje rozmiar twojego wektora i wypełni dowolną przestrzeń obiektami w ich domyślnym stanie. Jeśli są to liczby int, wszystkie będą miały wartość zero.Po dokonaniu rezerwacji, w twoim przypadku będziesz potrzebować dużo push_backs, aby napisać do elementu 5. Jeśli nie chcesz tego robić, w swoim przypadku powinieneś użyć resize.
Jedna rzecz dotycząca rezerwy: jeśli następnie dodasz elementy za pomocą push_back, dopóki nie osiągniesz zarezerwowanej pojemności, wszelkie istniejące odwołania, iteratory lub wskaźniki do danych w twoim wektorze pozostaną ważne. Więc jeśli zarezerwuję 1000, a mój rozmiar to 5,
&vec[4]
pozostanie taki sam, dopóki wektor nie będzie miał 1000 elementów. Potem mogę zadzwonićpush_back()
i zadziała, ale wcześniej zapisany wskaźnik&vec[4]
może już nie być ważny.źródło
std::vector::reserve
zapobiec sporadyczne kopiowanie pełnej tablicy napush_back
?< size()
kontenerze, jest niedozwolone. Z definicji języka ich tam nie ma. Jeśli twój kompilator zdecyduje się nie uruchamiać nukes i zamiast tego po prostu przegląda pamięć RAM w sposób, w jaki chcesz, to po prostu powodzenia. Albo chyba pecha; Idealnie byłoby, gdybyśmy wyłapali wszystkie nieprawidłowe rzeczy, które zrobiliby wszyscy programiści, ale powodzenia !Odpowiedział tutaj Jan Hudec : Wybór między vector :: resize () a vector :: Reserve ()
źródło
To zależy od tego, co chcesz robić.
reserve
ma nie dodawać żadnych elementów dovector
; zmienia tylkocapacity()
, co gwarantuje, że dodawanie elementów nie spowoduje realokacji (np. unieważni iteratory).resize
dodaje elementy natychmiast. Jeśli chcesz później dodać elementy (insert()
,push_back()
), użyjreserve
. Jeśli chcesz później uzyskać dostęp do elementów (używając[]
lubat()
), użyjresize
.MyClass::my_method
Możesz więc być: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 ); } }
lub
void MyClass::my_method() { my_member.resize( n_dim ); for ( int k = 0; k < n_dim; ++ k ) { my_member[k] = k; } }
Który z nich wybrałeś to kwestia gustu, ale cytowany kod jest wyraźnie nieprawidłowy.
źródło
Prawdopodobnie powinna być dyskusja na temat tego, kiedy obie metody są wywoływane z liczbą, która jest MNIEJSZA niż bieżący rozmiar wektora.
Połączenie
reserve()
z numerem mniejszym niż pojemność nie wpłynie na rozmiar ani pojemność.Wywołanie
resize()
z numerem mniejszym niż obecny rozmiar kontenera zostanie zmniejszony do tego rozmiaru, skutecznie niszcząc nadmiar elementów.Podsumowując
resize()
, zwolni pamięćreserve()
, ale nie.źródło
Tak, masz rację, Luchian właśnie popełnił literówkę i prawdopodobnie jest zbyt pozbawiony kawy, aby zdać sobie sprawę ze swojego błędu.
źródło
zmiana rozmiaru faktycznie zmienia liczbę elementów w wektorze, nowe elementy są domyślnie konstruowane, jeśli zmiana rozmiaru powoduje wzrost wektora.
vector<int> v; v.resize(10); auto size = v.size();
w tym przypadku rozmiar to 10.
rezerwa z drugiej strony tylko żąda powiększenia bufora wewnętrznego do określonego rozmiaru, ale nie zmienia „rozmiaru” tablicy, zmienia się jedynie rozmiar jej bufora.
vector<int> v; v.reserve(10); auto size = v.size();
w tym przypadku rozmiar nadal wynosi 0.
Odpowiadając na pytanie, tak, masz rację, nawet jeśli zarezerwujesz wystarczającą ilość miejsca, nadal uzyskujesz dostęp do niezainicjowanej pamięci za pomocą operatora indeksu. Z wartością int nie jest tak źle, ale w przypadku wektora klas miałbyś dostęp do obiektów, które nie zostały skonstruowane.
Sprawdzanie granic kompilatorów ustawionych na tryb debugowania może być oczywiście zdezorientowane przez to zachowanie, co może być przyczyną awarii.
źródło