Ce face std::vector::reserve
Un vector are două mărimi: size(), numărul de elemente, și capacity(), numărul de elemente pentru care are deja memorie. Când size() ajunge la capacity(), următorul push_back alocă o zonă mai mare și mută totul acolo.
reserve(n) alocă dinainte loc pentru cel puțin n elemente, fără să creeze elemente. Dacă știi câte vor fi, un singur reserve evită toate realocările. Dacă n este mai mare decât capacitatea, are loc o realocare și toți iteratorii, pointerii și referințele devin invalide; după aceea, cât timp size() <= n, push_back nu mai invalidează elementele existente.
shrink_to_fit() cere reducerea capacității la size(). Este doar o cerere: standardul permite implementării să o ignore (libc++ și libstdc++ o respectă). Dacă micșorează, realocă, deci invalidează și ea iteratorii.
Parametri
| Parametru | Descriere |
|---|---|
n |
Numărul minim de elemente pentru care să existe memorie. |
Ce returnează
reserve și shrink_to_fit: nimic. capacity: numărul de elemente care încap fără realocare.
Exemple
Exemplul 1: reserve evită realocările
Numărăm de câte ori se schimbă capacitatea în timp ce adăugăm 1000 de elemente. Numărul fără reserve depinde de bibliotecă (aici libc++).
#include <print>
#include <vector>
int realocari(bool cu_reserve) {
std::vector<int> v;
if (cu_reserve) {
v.reserve(1000);
}
int numar = 0;
std::size_t cap = v.capacity();
for (int i = 0; i < 1000; ++i) {
v.push_back(i);
if (v.capacity() != cap) {
++numar;
cap = v.capacity();
}
}
return numar;
}
int main() {
std::println("Fără reserve: {} realocări", realocari(false));
std::println("Cu reserve(1000): {} realocări", realocari(true));
}
Rezultat
Fără reserve: 11 realocări
Cu reserve(1000): 0 realocări
Exemplul 2: size, capacity și shrink_to_fit
#include <print>
#include <vector>
int main() {
std::vector<int> v;
v.reserve(100);
std::println("după reserve: size={} capacity={}", v.size(), v.capacity());
for (int i = 0; i < 10; ++i) {
v.push_back(i);
}
std::println("după 10 push_back: size={} capacity={}", v.size(), v.capacity());
v.shrink_to_fit();
std::println("după shrink_to_fit: size={} capacity={}", v.size(), v.capacity());
}
Rezultat
după reserve: size=0 capacity=100
după 10 push_back: size=10 capacity=100
după shrink_to_fit: size=10 capacity=10
Exemplul 3: Referință care rămâne validă datorită reserve
Capacitatea rezervată ajunge pentru toate elementele, deci vectorul nu se realocă și referința primul rămâne validă. Fără reserve, același cod ar fi comportament nedefinit.
#include <print>
#include <string>
#include <vector>
int main() {
std::vector<std::string> nume;
nume.reserve(10);
nume.push_back("Ana");
const std::string& primul = nume[0];
for (int i = 0; i < 5; ++i) {
nume.push_back("invitat"); // size ajunge la 6 <= 10: fără realocare
}
std::println("Primul: {}, total: {}, capacity: {}", primul, nume.size(), nume.capacity());
}
Rezultat
Primul: Ana, total: 6, capacity: 10
Greșeli frecvente
- Confunzi
reservecuresize: dupăv.reserve(10),v[0] = 1este comportament nedefinit, pentru că vectorul tot nu are elemente. - Apelezi
reserve(v.size() + 1)înainte de fiecarepush_back. Așa forțezi o realocare la fiecare pas și pierzi creșterea geometrică; apeleazăreserveo singură dată, cu numărul total. - Te bazezi pe o anumită valoare a capacității (de exemplu „se dublează”). Felul în care crește capacitatea depinde de bibliotecă (libc++ dublează, MSVC crește cu 50%).
Comenzi înrudite
std::vector::push_back: Adaugă un element la sfârșitul vectorului; vectorul crește cu o poziție.std::vector::resize: Schimbă numărul de elemente: adaugă elemente noi la final sau le șterge pe cele în plus.std::vector::size: size() spune câte elemente are vectorul; empty() spune dacă nu are niciunul.std::vector::clear: Șterge toate elementele vectorului; dimensiunea devine 0, dar memoria rezervată rămâne.std::unordered_map::reserve: reserve() pregătește tabela hash pentru n elemente; bucket_count() și load_factor() arată cât de încărcată este.