Transcript STL

C++
wykład 13,14,15
(16/23/30.05.2012)
STL
STL






STL (ang. Standard Template Library) to
standardowa biblioteka wzorców w C++.
Wszystkie składniki STL są wzorcami.
STL jest rdzeniem biblioteki standardowej C++.
Wszystkie identyfikatory w bibliotece standardowej
C++ zdefiniowane są w przestrzeni nazw std.
Zaleta STL – mnóstwo gotowych szablonów klas
pozwalających programować na wyższym poziomie
abstrakcji.
Wada STL – brak oczywistości (koniecznie czytaj
dokumentację)
STL

Biblioteka STL składa się z kilku modułów:




kontenery (sekwencyjne, asocjacyjne),
iteratory (dwukierunkowe, z dostępem
swobodnym),
algorytmy,
a także funktory (obiekty funkcyjne, predykaty),
łańcuchy, strumienie.
Pary







Szablon struktury pair<> (zdefiniowany w <utility>) umożliwia
potraktowanie dwóch wartości jako pojedynczego elementu.
Para posiada dwa pola: first i second.
Para posiada konstruktor dwuargumentowy oraz domyślny i kopiujący.
Pary można porównywać (operatory == i <).
Istnieje szablon funkcji make_pair() do tworzenia pary.
Przykłady:
void f (std::pair<int, const char *>);
void g (std::pair<const int, std::string>);
…
std::pair<int, const char *> p(44,”witaj”);
f(p); // wywołuje domyślny konstruktor kopiujący
g(p); // wywołuje konstruktor wzorcowy
g(std::make_pair(44,”witaj”)); // przekazuje dwie
// wartości jako parę z wykorzystaniem konwersji
// typów
Pary są wykorzystywane w kontenerach map i multimap.
Ograniczenia liczbowe



Typy numeryczne posiadają ograniczenia zależne od platformy i
są zdefiniowane w szablonie numeric_limits<>
(zdefiniowany w <limits>, stałe preprocesora są nadal
dostępne w <climits> i <cfloat>).
Wybrane składowe statyczne szablonu numeric_limits<>:
is_signed, is_integer, is_exact, is_bounded,
is_modulo, has_infinity, has_quiet_NaN,
min(), max(), epsilon().
Przykłady:
numeric_limits<char>::is_signed;
numeric_limits<short>::is_modulo;
numeric_limits<long>::max();
numeric_limits<float>::min();
numeric_limits<double>::epsilon();
Minimum i maksimum


Obliczanie wartości minimalnej oraz maksymalnej:
template <class T>
inline const T& min (const T &a, const
{ return b<a ? b : a; }
template <class T>
inline const T& max (const T &a, const
{ return a<b ? b : a; }
Istnieją też wersje tych szablonów z komparatorami
funkcyjny):
template <class T, class C>
inline const T& min (const T &a, const
{ return comp(b,a) ? b : a; }
template <class T>
inline const T& max (const T &a, const
{ return comp(a,b) ? b : a; }
T &b)
T &b)
(funkcja lub obiekt
T &b, C comp)
T &b, C comp)
Minimum i maksimum


Przykład 1:
bool int_ptr_less (int *p, int *q) {
return *p<*q; }
…
int x = 33, y = 44;
int *px = &x, *py = &y;
int *pmax = std::max(px,py,int_ptr_less);
Przykład 2:
int i;
long l;
…
l = max(i,l); // BŁĄD
// niezgodne typy argumentów
l = std::max<long>(i,l); // OK
Zamiana wartości


Zamiana dwóch wartości:
template <class T>
inline void swap (T &a, T &b)
{ T tmp(a); a = b; b = tmp; }
Przykład:
int x = 33, y = 44;
…
std::swap(x,y);
Operatory porównywania



Cztery funkcje szablonowe (zdefiniowane w <utility>) na podstawie
operatorów == i < definiują operatory porównań !=, <=, >= i >.
Funkcje te są umieszczone w przestrzeni nazw std::rel_ops.
Przykład:
class X {
…
public:
bool operator== (const X &x) const throw();
bool operator< (const X &x) const throw();
…
};
…
void foo () {
using namespace std::rel_ops;
X x1, x2;
…
if (x1!=x2) { … }
…
}
Kontenery


Kontenery służą do przechowywania i
zarządzania kolekcjami danych.
Rodzaje kontenerów:

Kontenery sekwencyjne, gdzie każdy element ma
określoną pozycję. Na przykład: vector, deque,
list.

Kontenery uporządkowane (w tym asocjacyjne),
gdzie pozycja elementu zależy od jego wartości.
Na przykład: set, multiset, map, multimap.
Elementy kontenerów

Elementy kontenerów muszą spełniać wymagania
podstawowe:




element musi być kopiowalny (konstruktor kopiujący),
element musi być przypisywalny (przypisanie kopiujące),
element musi być zniszczalny (publiczny destruktor).
W pewnych sytuacjach elementy kontenerów muszą
spełniać wymagania dodatkowe:



konstruktor domyślny (utworzenie niepustego kontenera),
operator porównywania == (wyszukiwanie),
operator porównywania < (kryterium sortowania).
Semantyka wartości
a semantyka referencji


Kontenery STL realizują semantykę wartości:
tworzą wewnętrzne kopie swoich elementów
oraz zwracają kopie tych elementów.
Semantykę referencji można
zaimplementować samodzielnie za pomocą
inteligentnych wskaźników – wskaźniki te
mają umożliwiać zliczanie referencji dla
obiektów, do których odnoszą się wskaźniki.
Kontenery sekwencyjne
– wektory




Wektor vector<> (zdefiniowany w <vector>) przechowuje
swoje elementy w tablicy dynamicznej.
Uzyskujemy szybki dostęp do każdego elementu za pomocą
indeksowania.
Dołączanie i usuwanie elementów na końcu wektora jest bardzo
szybkie, ale wstawienie lub usunięcie elementu ze środka
zabiera więcej czasu.
Przykład:
vector<int> coll;
…
for (int i=1; i<=6; ++i)
coll.push_back(i);
…
for (int i=0; i<coll.size(); ++i)
cout << coll[i] << ’ ’;
cout << endl;
Kontenery sekwencyjne
– kolejki o dwóch końcach




Kolejka o dwóch końcach deque<> (zdefiniowana w <deque>)
przechowuje swoje elementy w tablicy dynamicznej, która może rosnąć
w dwie strony.
Uzyskujemy szybki dostęp do każdego elementu za pomocą
indeksowania.
Dołączanie i usuwanie elementów na końcu i na początku kolejki jest
bardzo szybkie, ale wstawienie lub usunięcie elementu ze środka
zabiera więcej czasu.
Przykład:
deque<float> coll;
…
for (int i=1; i<=6; ++i)
coll.push_front(i*1.234);
…
for (int i=0; i<coll.size(); ++i)
cout << coll[i] << ’ ’;
cout << endl;
Kontenery sekwencyjne
– listy




Lista list<> (zdefiniowana w <list>) przechowuje swoje
elementy w liście dwukierunkowej.
W listach nie ma swobodnego dostępu do elementów kolekcji.
Dołączanie i usuwanie elementów na końcu i na początku listy
jest bardzo szybkie, ale dostanie się do elementu ze środka
zabiera dużo czasu.
Przykład:
list<char> coll;
…
for (char c=’a’; c<=’z’; ++c)
coll.push_back(c);
…
while (!coll.empty()) {
cout << coll.front() << ’ ’;
coll.pop_front(); }
cout << endl;
Kontenery sekwencyjne
– łańcuchy i tablice


Obiektów klas łańcuchowych, czyli
basic_string<>, string i wstring,
można używać jak kontenerów
sekwencyjnych. Są one podobne w
zachowaniu do wektorów.
Innym rodzajem kontenera może być tablica.
Nie jest to klasa i nie ma żadnych metod ale
konstrukcja STL umożliwia uruchamianie na
tablicach różnych algorytmów (tak jak na
kontenerach).
Kontenery uporządkowane






Kontenery uporządkowane wykonują automatycznie sortowanie
swoich elementów.
Asocjacyjne kontenery uporządkowane przechowują pary kluczwartość (odpowiednio first i second) i sortowanie następuje
po kluczach.
Domyślnie elementy lub klucze są porządkowane przy pomocy
operatora <.
Kontenery uporządkowane są implementowane w postaci
zrównoważonych drzew BST (drzewa czerwono-czarne).
Wszystkie kontenery uporządkowane posiadają domyślny
parametr wzorca służący sortowaniu (domyślnym jest operator
<).
Rodzaje kontenerów: zbiory set<>, wielozbiory multiset<>,
mapy map<> i multimapy multimap<>.
Adaptatory kontenerów


Adaptatory kontenerów to kontenery
wykorzystujące ogólną strukturę innych
kontenerów do realizacji pewnych
specyficznych potrzeb.
Adaptatorami kontenerów są stosy
stack<>, kolejki queue<> i kolejki
priorytetowe priority_queue<>.
Iteratory




Iterator to specjalny obiekt, który potafi iterować po elementach
kolekcji.
Iterator ma zaimplementowaną semantykę wskaźnika – posiada
operator wyłuskania elementu *, operatory przechodzenia do
elementówsąsiednich ++ i -- oraz operatory porównywania
pozycji == i !=.
Wszystkie kontenery udostępniają funkcje tworzące iteratory do
nawigowania po ich elementach – funkcja begin() zwraca
iterator wskazujący na pozycję z pierwszym elementem w
kolekcji a funkcja end() zwraca iterator wskazujący pozycję za
ostatnim elementem.
Każdy kontener definiuje dwa typy iteratorów –
kontener::iterator przeznaczony do iterowania po
elementach z możliwością odczytu i zapisu oraz
kontener::const_iterator przeznaczony do iterowania po
elementach tylko z możliwością odczytu.
Iteratory


Przykład 1:
list<char> coll;
…
list<char>::const_iterator pos;
for (pos=coll.begin(); pos!=coll.end(); ++pos)
cout << *pos << ’ ’;
cout << endl;
Przykład 2:
list<char> coll;
…
list<char>::iterator pos;
for (pos=coll.begin(); pos!=coll.end(); ++pos)
*pos = toupper(*pos);