STL: Lekcja 1&2 Tematy: Filozofia STL Po co nam STL? Podstawowa zawartość STL Co warto znać zanim zaczniemy pracę z STL?: wskaźniki Praca na tekstach: klasa String Vector: nowy wymiar standardowych tablic. Filozofia STL STL (ang. Standard Template Library) czyli biblioteka standardowa. STL jest pewną częścią biblioteki standardowej C++, jednak nie całą. Dobrze jest się go nauczyć zaraz po samej nauce czystego C++. Po co nam STL? Przede wszystkim po to, by nie odkrywać niektórych rzeczy na nowo. Są w niej zawarte wzorce konkretnych komponentów, które mogą być szeroko wykorzystywane na wielu platformach. Zawartość STL W STL'u zawarte są: kontenery - Kontener (lub inaczej pojemnik, ang. container, collection) to struktura danych, której zadaniem jest przechowywanie w zorganizowany sposób zbioru danych (obiektów). Kontener zapewnia narzędzia dostępu, w tym dodawanie, usuwanie i wyszukiwanie danej (obiektu) w kontenerze. W zależności od przyjętej organizacji, poszczególne kontenery różnią się wydajnością poszczególnych operacji. Mamy dwa typy kontenerów: kontenery i kontenery asocjacyjne. iteratory - W programowaniu obiektowym iteratorem nazywamy obiekt pozwalający na sekwencyjny dostęp do wszystkich elementów lub części zawartych w innym obiekcie, zwykle kontenerze lub liście. Iterator jest czasem nazywany kursorem, zwłaszcza w zastosowaniach związanych z bazami danych. algorytmy dobrze znana nam nazwa, w STL'u odgrywa rolę taką, że są to funkcje, które mają wykonywać pewne abstrakcyjne działania. Przykłady kontenerów: Kontenery Vector List Deque Kontenery asocjacyjne Set Map Multimap Multiset Zanim zaczniemy podróż po krainie STL... Wskaźniki: Element, który pokazuje na inną zmienną i zawiera adres do elementu na który pokazuje. Definicja wskaźnika wygląda następująco: TYP *nazwa_zmiennej; Przykłady: int *x; x jest zmienną wskaźnikową zawierającą adres do zmiennych typu całkowitego double *y; - y jest zmienną wskaźnikową zawierającą adres do typu zmiennoprzecinkowego
int *w; /* wskaźnik na zmienną typu int */ int a = 100; int b; w = &a; /* wskaźnik 'w' wskazuje na zmienną typu int 'a' */ b = *w; /* przypisz zmiennej 'b' wartość spod adresu wskazywanego przez 'w'; teraz 'b' równe jest 100 */ Powyższe działanie nazywamy wyłuskiwaniem lub adresowaniem pośrednim pobranie adresu zmiennej i przypisanie go pod zmienną wskaźnikową. Iteratory: Iteratory zostały stworzone z myślą o pracy na kontenerach. (tj. np. Vector, List). Umożliwiają docieranie do interesujących nas elementów bez znajomości struktury danego obiektu. Iteratory to pewien rodzaj wskaźników, przy czym w przypadku iteratorów nie musimy martwić się o przejście zakresu pojemnika oraz o to, czy poprawnie wskazuje na interesujący nas element. Na ryzie tyle o iteratorach. Więcej o nich porozmawiamy w przypadku konkretnego kontenera wektora. Operacje na tekstach klasa String Zanim przejdziemy do czystych struktur STL zajmiemy się klasą String, czyli klasą, która pozwoli nam manipulować łancuchami (napisami). W przypadku wszystkich elementów STL'a będziemy zawsze na samym początku wykorzystywać następującą deklarację: #include <string> W tym momencie do naszego programu obok takich rzeczy, jak iostream dołączyliśmy obsługę napisów. Teraz w głównym programie możemy zadeklarować zmienne typu łańcuchowego. Wygląda to w następujący sposób: string s; string k,l,m; itd. Ponadto możemy stworzyć taki łańcuch o określonej długości i/lub zawartości. Np. string s(10, K ); Gdy wyświetlimy zawartość zmiennej s na ekranie pojawi się: KKKKKKKKKK. Kolejnym ważnym elementem jest to, że na stringach możemy wykonywać podobne czynności jak w przypadku liczb: +,==,+=,!= oraz do poszczególnych zawartości łańcucha odwołujemy się jak do tablicy tj. nazwa_stringu[index_elementu]; Jak widać manipulacje obiektami string są bardzo wygodne. Oprócz wygodnych w stosowaniu operatorów klasa string posiada jeszcze więcej metod. Metoda empty() size(),length() at() Opis Zwraca wartość true jeżeli napis jest pusty. Zwraca ilość znaków w napisie. Zwraca znak o podanym położeniu, podobnie jak operator [] z tym że ta metoda jest bezpieczniejsza, zapobiega wyjściu poza zakres.
clear(),erase() Usuwa wszystkie znaki z napisu, erase() może usuwać wybrane znaki. find() Znajduje podciąg w ciągu, są też bardziej rozbudowane funkcje tego typu. swap() Zamienia miejscami dwa stringi, a staje sie b, a b staje sie a. append() Dodaje zadany napis na końcu istniejącego ciągu. c_str() Zwraca napis w stylu języka C (stały wskaźnik do pierwszego elementu). Vector nowe spojrzenie na tablicę Klasa Vector reprezentuje klasyczną tablicę standardową. Możemy tworzyć wektory dowolnych typów. Aby zacząć korzystać z wektorów, w nagłówku należy napisać: #include <vector> Od tego momentu mamy możliwość tworzyć obiekty klasy vector. Aby utworzyć taki obiekt, stosuje się jedną z metod. Przykłady: vector < typ_elemetow > nazwa_tablicy; - definicja vector < int > tab(20); - utwórz wektor typu całkowitego o nazwie tab i rozmiarze 20. vector < string > tablica( 20, "przykladowy tekst dla kazdego elementu"); - utwórz wektor typu łańcuchowego o nazwie tablica, rozmiarze 20 i dla każdego elementu przypisz tekst przykladowy tekst dla kazdego elementu Uwaga, teraz jedna z ciekawszych rzeczy przy deklaracji wektorów nie trzeba podawać jego rozmiaru! Nasz wektor będzie się dostosowywał wielkością do ilości elementów wprowadzanych do niego. Kiedy mamy już taki wektor, czas na manipulacje nim. Z pomocą do pracy nad nimi przychodzą iteratory. kontener<typ_kontenera>::iterator nazwa_iteratora; - definicja W przypadku pracy na kontenerach zazwyczaj tworzymy sobie dwa iteratory jeden, który wskazuje na pierwszy element i drugi wskazujący na ostatni element. vector<string>::iterator iter1; vector<string>::iterator iter2; iter1 = tabstr.begin(); iter2 = tabstr.end(); Z iteratorów możemy korzystać jak ze zwykłych wskaźników możemy wykonywać operacje arytmetyczne, logiczne, a ponadto jeszcze używać [] jak w przypadku tablic. #include <string> #include <iostream> #include <vector> using namespace std;
int main() { vector<string> tabstr(10,"0"); vector<string>::iterator iter1; vector<string>::iterator iter2; iter1 = tabstr.begin(); iter2 = tabstr.end(); for (int a = 0; iter1!= iter2; ++iter1, ++a ) { if (a % 2 == 0) *iter1 = "1"; cout << *iter1 << endl; } return 0; } Operacje na wektorach: operacje void swap(vector vec) size_t size() size_t capacity() size_t max_size() bool empty() void reserve(size_t n) void resize(size_t n, T obj) void resize(size_t n) void push_back(const T obj) void pop_back() czasie) opis działania zamienia zawartości dwóch wektorów miejscami (wykonywane szybko, w stałym czasie) zwraca obecną ilość elementów wektora. zwraca ilość elementów, którą wektor jest w stanie pomieścić przed przeniesieniem go do większego obszaru pamięci. zwraca ilość elementów, którą maksymalnie może pomieścić wektor zwraca true jeśli wektor nie przechowuje żadnych zmiennych rezerwuje pamięć na n elementów, co zapobiega przenoszeniu wektora w pamięci przed osiągnięciem tej liczby zmienia rozmiar wektora do n; jeśli jest większy od obecnego, dodawane są nowe elementy będące kopiami obj zmienia rozmiar wektora do n; jeśli jest większy od obecnego, dodawane są nowe elementy o przypadkowych wartościach dodaje na końcu wektora kopię przekazanego argumentu usuwa ostatni element z wektora (wykonywane w stałym
void clear() void assign(size_t n, const T obj) usuwa wszystkie elementy z wektora czyści wektor i wypełnia go n kopiami argumentu obj iterator assign(iterator poczatek, iterator koniec) czyści wektor i wypełnia go elementami z innego wektora z przedziału <poczatek;koniec> iterator insert(iterator pos, T obj) void insert(iterator pos, size_t n, const T obj) wstawia element obj przed wskazywaną przez iterator pos pozycją i zwraca iterator do dostawionego elementu (powolna funkcja) wstawia n kopii argumentu obj przed pozycją wskazywaną przez iterator pos void insert(iterator pos, iterator poczatek, iterator koniec) wstawia przed pozycją wskazywaną przez iterator pos elementy między iteratorami początek i koniec (włącznie) iterator erase(iterator pos) iterator erase(iterator poczatek, iterator koniec) T& front() T& back() iterator begin() iterator end() iterator rbegin() iterator rend() usuwa element wskazywany przez pos i zwraca iterator do następnego elementu usuwa elementy z przedziału <poczatek;koniec> i zwraca iterator do elementu za nimi zwraca referencję do pierwszego elementu wektora zwraca referencję do ostatniego elementu wektora zwraca iterator do pierwszego elementu wektora (często mylone z front()) zwraca iterator ustawiony za ostatnim elementem wektora zwraca odwrócony iterator do pierwszego elementu zwraca odwrócony iterator do ostatniego elementu