-
Cache-friendly
- Elementy są ZAWSZE ułożone obok siebie w pamięci, tak jak w zwykłej tablicy
-
Iterując po
std::vector<T>
, kolejne jego elementy będą ładowane do pamięci podręcznej procesora z wyprzedzeniem, co niesamowicie przyspieszy odczytywanie danych (oraz modyfikację, jeśli robimy to jednowątkowo)
-
Typ
T
może być dowolny. Zarówno typ wbudowany jakint
,double
, jak i własny zdefiniowany przez nas typ. -
Dodawanie/usuwanie elementów na końcu jest:
- szybkie jeśli
size() < capacity()
- kosztowne w przeciwnym przypadku, gdyż zachodzi alokacja dodatkowej pamięci na nowe elementy
- szybkie jeśli
- Dodawanie/usuwanie z początku oraz środka jest kosztowne, gdyż należy przesunąć o 1 pozycję wszystkie kolejne elementy, aby zachować ciągłość wektora
-
W praktyce jednak pamięć cache tak bardzo przyspiesza pracę z
std::vector
, że nawet dodawanie/usuwanie elementów ze środka często będzie szybsze niż w innych kontenerach
Operacja | Metody |
---|---|
dodawanie elementu | push_back() , emplace_back() , insert() , emplace() |
modyfikowanie/dostęp do elementu | at() , operator[] |
pierwszy/ostatni element | back() , front() |
rozmiar | size() |
zarezerwowane miejsce | capacity() |
rezerwowanie miejsca w pamięci | reserve() |
wyczyszczenie nieużywanej pamięci z wektora | shrink_to_fit() |
odwrócony (ang. reverse) iterator | rbegin() , rend() |
stały iterator | cbegin() , cend() , crbegin() , crend() |
wyczyszczenie kontenera | clear() |
przygotowanie elementu do usunięcia | std::remove() (nie jest metodą std::vector<T> ) |
wymazanie elementów z pamięci | erase() |
void push_back( const T& value );
void push_back( T&& value );
template< class... Args >
reference emplace_back( Args&&... args );
struct Point2D {
int x;
int y;
};
std::vector<Point2D> vec{{1, 1}, {2, 0}, {-3, 10}};
vec.push_back({5, 2});
vec.emplace_back(5, 2);
iterator insert( const_iterator pos, const T& value );
W celu dodania elementu do wektora, możemy wykorzystać iterator:
std::vector<int> vec{1, 2, 3, 4};
auto it = vec.begin();
vec.insert(it, 20); // {20, 1, 2, 3, 4};
iterator insert( const_iterator pos, size_type count, const T& value );
Możemy także określić ile elementów chcemy dodać:
std::vector<int> vec{1, 2, 3, 4};
auto it = vec.begin();
vec.insert(it, 5, 20); // {20, 20, 20, 20, 20, 1, 2, 3, 4};
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );
Istnieje też możliwość wstawienia elementów z jednego kontenera do drugiego:
std::vector<int> vec{1, 2, 3, 4};
std::list<int> list{10, 20, 30, 40};
vec.insert(vec.begin() + 2, list.begin(), list.end());
// vec = {1, 2, 10, 20, 30, 40, 3, 4}
std::vector<int> vec {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto it = vec.crbegin() ; it != vec.crend() ; ++it) {
// cr = (r)everse iterator to (c)onst value
std::cout << *it << ' ';
}
Output: 9 8 7 6 5 4 3 2 1
std::vector<int> vec {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto it = vec.rbegin() ; it != vec.rend() ; ++it) {
*it *= 2;
}
for (auto it = vec.crbegin() ; it != vec.crend() ; ++it) {
std::cout << *it << ' ';
}
Output: 18 16 14 12 10 8 6 4 2
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
Ponieważ najszybciej usuwane są elementy z końca wektora, biblioteka STL umożliwia nam przygotowanie std::vector<T>
do usunięcia elementów poprzez przeniesienie tych nieprzeznaczonych do usunięcia na początek kontenera.
W wyniku tego część wartości do usunięcia jest nadpisywana wartościami z końca wektora, które nie powinny zostać usunięte.
Na końcu wektora pozostają "śmieci", które należy wymazać (ang. erase) z pamięci.
std::vector<int> vec{1, 4, 2, 4, 3, 4, 5};
std::remove(vec.begin(), vec.end(), 4);
// for example: vec {1, 2, 3, 5, 3, 4, 5}
std::remove()
zwróci nam iterator, który wskaże początek danych przeznaczonych do usunięcia.
iterator erase( const_iterator first, const_iterator last );
Dzięki metodzie erase, możemy teraz usunąć niepotrzebne dane z kontenera:
std::vector<int> vec{1, 4, 2, 4, 3, 4, 5};
auto it = std::remove(vec.begin(), vec.end(), 4);
vec.erase(it, vec.end());
// vec {1, 2, 3, 5}
Możemy też zapisać to wszystko w jednej linii (Erase-Remove Idiom)
vec.erase(std::remove(vec.begin(), vec.end(), 4), vec.end());
- Otwórz dokumentację wektora na cppreference.com
- Stwórz nowy plik i napisz funkcję
main()
- Stwórz wektor o wartościach
{1, 2, 4, 5, 6}
- Usuń pierwszą wartość
- Dodaj wartość 5 na końcu wektora
- Dodaj wartość 12 na początku wektora metodą
emplace
- Wypisz rozmiar wektora i maksymalny możliwy rozmiar
- Wypisz zawartość wektora
- Wyczyść wektor
- Wypisz rozmiar wektora
- Otwórz dokumentację wektora na cppreference.com
- Stwórz nowy plik i napisz funkcję
main()
- Stwórz pusty wektor
- Wypisz rozmiar i pojemność wektora
- Zmień rozmiar wektora na 10 i wypełnij go wartościami 5
- Wypisz rozmiar i pojemność wektora
- Zarezerwuj pamięć na 20 elementów
- Wypisz rozmiar i pojemność wektora
- Zredukuj pojemność wektora metodą
shrink_to_fit()
- Wypisz rozmiar i pojemność wektora