STL Standard Template Library 2 STL od źrdeł czyli

Document Sample
STL Standard Template Library 2 STL od źrdeł czyli Powered By Docstoc
					   STL - Standard Template Library 2
(STL od źródeł, czyli specyfikacja biblioteki)




  Autor: Błażej Chodarcewicz
  rainbow.mimuw.edu.pl/~bc189380/STL/
Standard C++ (STL)
 Organizacja pracująca nad standardem
  http://anubis.dkuug.dk/jtc1/sc22/wg21/
 Wersja Draft 1996 r.
 ISO-IEC 14882 Programming.Language.C++ (1998)
 ISO/IEC 14882:2003
Jak to działa?
Iteratory
 Uogólnienie wstaźników
 Umożliwiają pracę z kontenerami w ujednolicony sposób
 Biblioteka formalizuje interfejs, semantykę oraz założenia
  złożonościowe
 Semantyka iteratorów jest uogólnieniem semantyki wskaźników
 Wyrażenie *i – wartością jest obiekt pewnej klasy, enumeracja lub
  typ wbudowany T, zwany value type of iterator
 Wszystkie iteratory i, dla których (*i).m jest zdefiniowane, wspierają
  także wyrażenie i->m
 Dla każdego iteratora typu X, dla którego zdefiniowana jest
  równość, jest dostępny typ difference type iteratora
Rodzaje iteratorów

input iterators
output iterators
forward iterators
bidirectional iterators
random access iterators
Relacje pomiędzy iteratorami

             Input      Output


                Forward


              Bidirectional


             Random Access
Iteratory zmienialne i niezmienialne

mutable, constant iterators
*i jako referencja lub referencja do stałej
Iteratory stałe nie spełniają wymagań output
 iterators
past-the-end value

 Dla każdego iteratora istnieje wartość wskazująca na element
  za ostatnim elementem kolekcji, z którą związany jest iterator
 dereferencable values
 Biblioteka nigdy nie zakłada, że past-the-end value jest
  dereferencable
Kilka definicji
 Iterator i jest reachable z iteratora i wtw., gdy istnieje skończona
  sekwencja aplikacji wyrażenia ++i, po której mamy i == j.
 Jeśłi i jest reachable z j, to i i j odnoszą się do tej samej kolekcji
 Range – para iteratorów, które określają początek i koniec obliczeń
 Range [i, i) – empty range
 W ogólności range [i, j) odnosi się do elementów struktury danych
  zaczynających się od elementu wskazywanego przez i, kończących
  się na elemencie wskazywanym przez j bez tego elementu
 Range [i, j) jest prawidłowe wtw., gdy j jest reachable z i. Aplikacja
  algorytmu dla nieprawidłowego Range jest nieokreślona
Kilka założeń

Złożoność (zamortyzowana) wszystkich operacji
 wymaganych dla danej kategorii iteratora jest
 stała
Na następnych slajdach występują:
 a, b oznaczają wartości iteratora X, n oznacza
 wartość typu difference type Distance; u, tmp i
 m oznaczają identyfikatory, r oznacza wartość
 X&, t oznacza wartość typu wartości iteratora -
 T.
Input iterator - wymagania
 Operacja      Typ                      Semantyka, założenia
  X u(a);       X                         post: u jest kopią a
                              Destruktor musi być zdefiniowany i dostępny.
  u = a;        X                                 wynik: u
                                            post: u jest kopią a
  a == b    convertible      == jest relacją równości (w matematycznym sensie)
              to bool           zdefiniowaną na dziedzinie wartości iteratora
  a != b    convertible          bool(a==b) != bool(a!=b) dla dziedziny ==
              to bool
    *a          T                        pre: a jest dereferenceable
                          Jeśli a==b i (a,b) należy do dziedziny relacji ==, wtedy
                                          *a jest takie samo jak *b.
   a->m                           pre: (*a).m jest dobrze zdefiniowane
                                  Semantyka jest taka sama jak (*a).m
Input iterator – wymagania c.d.
 Operacja     Typ                  Semantyka, założenia
    ++r       X&                     pre: r jest dereferenceable
                    post: r jest dereferenceable lub r jest wartością past-the-
                                                  end
                    post: każda kopia poprzednij wartości r nie musi już być
                         ani dereferenceable, ani nawet nie musi być w
                                             dziedzinie ==
  (void)r++                          taka sama jak (void)++r

    *r++       T                 { T tmp = *r; ++r; return tmp; }
Input iterator – uwagi

a == b nie implikuje ++a == ++b
Algorytmy nigdy nie powinny próbować
 przechodzi po tym samym iteratorze dwa razy
Typ wartości T nie musi być typem lvalue
 (Przykład istream_iterator)
Output iterator - wymagania
 Operacja   Zwracany                 Semantyka, założenia
              typ
   X(a)          X              a = t jest takie samo jak X(a) = t
                              Zakłada się obecność destruktora
  X u(a);                     SGI: pre: a musi być zainicjalizowane
 X u = a;                     post: *a = t jest takie samo jak *u = t

  *a = t    nieużywany            SGI: pre: a jest dereferencable
                            po poprzednim przypisaniu było wykonane
                                          zwiększenie a
   ++r          X&                         &r == &++r
   r++      konwertowalny   { X tmp = r; const X& ++r; return tmp; }
             do const X&

 *r++ = t    nieużywany
Output iterator - uwagi

operator * może zostać użyty jedynie po lewej
 stronie wyrażenia przypisania
przypisanie poprzez wartość iteratora odbywa
 się tylko raz
nigdy nie należy przechodzić po tych samych
 wartościach iteratora więcej niż raz
== i != mogą być niezdefiniowane
Forward iterator - wymagania
 Operacja       Typ                   Semantyka, założenia
   X u;                    u może być niezainicjowane, zakładane jest istnienie
                                               destruktora
  X u(a);        X                      równoważne: X u; u = a;
  X u = a;                                   post: u == a
   X(a)          X                             X(a) == a

  a == b     convertible   == jest relacją równości (w matematycznym sensie)
               to bool        zdefiniowaną na dziedzinie wartości iteratora
   a != b    convertible                        !(a==b)
               to bool
   r=a          X&                             post: r == a
Forward iterator – wymagania c.d.
 Operacja       Typ                      Semantyka, założenia
    *a           T&                       pre: a jest dereferenceable
                                           Jeśli a == b, to *a == *b
                                Jeśli X jest typem mutowalnym, to *a = t jest
                                                    poprawne
   a->m                             pre: (*a).m jest dobrze zdefiniowane
                                    Semantyka jest taka sama jak (*a).m
   ++r          X&                         pre: r jest dereferenceable
                            post: r jest dereferenceable lub r jest wartością past-
                                                      the-end
                             Jeśli r == s i r jest dereferencable, to ++r == ++s.
                                                    &r == &++r
   r++      konwertowalny              { X tmp = r; ++r; return tmp; }
             do const X&
   *r++          T&
Bidirectional iterator – dodatkowe wymagania
  Operacja       Typ            Semantyka, założenia
     --r         X&          pre: istnieje s takie, że r == ++s.
                               post: r jest dereferenceable.
                                  Jeśli –r == --s, to r == s.
                                          &r == &--r.
                                          --(++r) = r.
     r--     konwertowalny    { X tmp = r; --r; return tmp; }
              do const X&
    *r--     konwertowalny
                 do T
Random access iterator - wymagania
 Operacja    Typ                  Semantyka, założenia
  r += n      X&                       { Distance m = n;
                       if (m >= 0) while (m--) ++r; else while (m++) --r;
                                           return r; }
   a+n         X                          { X tmp = a;
   n+a                                 return tmp += n; }
                                   założenie: a + n == n + a
   r -= n     X&                         return r += -n;

   a–n         X                          { X tmp = a;
                                       return tmp -= n; }
   b–a      Distance      pre: Istnieje wartość n typu Distance taka, że
                                            a + n == b.
                                         b == a + (b – a).
                            (a < b) ? distance(a, b) : -distance(b, a).
Random access iterator – wymagania c.d.
 Operacja       Typ            Semantyka, założenia
   a[n]     konwertowalny                *(a + n)
                do T
   a<b      konwertowalny        true wtw., gdy b – a > 0.
               do bool      > jest relacją porządku liniowego.
   a>b      konwertowaln            równoważne z b < a.
              y do bool      > jest relacją porządku liniowego
  a <= b    konwertowaln         takie samo jak: !(a > b)
              y do bool
  a >= b    konwertowaln          takie samo jak: !(a < b)
              y do bool
Przykłady
 int main(){
         int array [1000], *i;
         int n = 0;
         i = array;
         while (cin >> *i) ++i;
         ++i;
         sort (array, i);
         for (j = array; i != j; j++) cout << *j << "\n";
 }
Przykład
int main () {
       vector<int> v;
       int input;
       while (cin >> input) v.push_back (input);
       sort(v.begin(), v.end());
       for (vector<int>::iterator i = v.begin(); i != v.end(); i++)
               cout << *i << "\n";
}
Obiekty funkcyjne

 Obiekty funkcyjne to obiekty, które mają zdefiniowany
  operator ()
 Są ważną częścią biblioteki STL, zapewniają one efektywność
 Wszędzie tam, gdzie szablony algorytmów oczekują
  wskaźników do funkcji, można stosować obiekty funkcyjne
 Używanie obiektów funkcyjnych razem z szablonami funkcji
  zwiększa siłę wyrazu biblioteki, a także zwiększa efektywność
  kodu
Obiekty funkcyjne – przykłady

dodanie elementów dwóch wektorów
 (double) a, b do siebie

 transform(a.begin(), a.end(), b.begin(), a.begin(), plus<double>());


zanegowanie wszystkich elementów a:

 transform(a.begin(), a.end(), a.begin(), negate<double>());
Obiekty funkcyjne

 template <class Arg, class Result> struct
 unary_function {
       typedef Arg argument_type;
       typedef Result result_type;
 };

 template <class Arg1, class Arg2, class Result>
 struct binary_function {
         typedef Arg1 first_argument_type;
         typedef Arg2 second_argument_type;
         typedef Result result_type;
 };
Obiekty funkcyjne – przykłady
 template <class T> struct plus : binary_function<T,T,T> {
      T operator()(const T& x, const T& y) const;
  };

   Obiekt funkcyjny obliczający x + y.

 template <class T> struct negate : unary_function<T,T> {
      T operator()(const T& x) const;
  };

   Obiekt funkcyjny obliczający –x.
 Obiekty funkcyjne – przykłady
 template <class Operation> class binder1st
  : public unary_function<Operation::second_argument_type,
  Operation::result_type> {
  protected:
       Operation op;
       Operation::first_argument_type value;
  public:
       binder1st(const Operation& x, const
  Operation::first_argument_type& y);
       result_type operator()(const argument_type& x) const;
  };
 Konstruktor inicjalizuje op na x, value na y
 Operator () zwraca op(value, x)
 template <class Operation, class T>
  binder1st<Operation> bind1st(const Operation& op, const T& x);
EqualityComparable

 Typ T jest EqualityComparable jeśli ma
 zdefiniowany operator ==, którego wynik jest
 konwertowalny do bool oraz
== jest relacją równości spełniającą założenia:
 - Dla każdego a: a == a
 - Jeśli a == b, to b == a
 - Jeśli a == b i b == c, to a == c
   Algorytmy Non-mutating
 template <class InputIterator, class UnaryFunction>
  UnaryFunction for_each(InputIterator first, InputIterator last,
  UnaryFunction f);

  Efekt: Zaaplikowanie f do wyników dereferencii kolejnych wartości
  iteratora w przedziale [first, last), zaczynając od first i kontynuując aż do
  last - 1.
  Wymagania: f nie powinno wywoływać żadnych funkcji, które nie są
  zadeklarowane jako stałe dla wartości iteratora.
  Zwraca: f.
  Złożoność: f jest wywoływana dokładnie last - first razy.
  Uwaga: Jeśli f zwraca jakąś wartość wynik jest ignorwany.
 template <class InputIterator, class EqualityComparable>
  iterator_traits<InputIterator>::difference_type count(InputIterator first,
  InputIterator last, const EqualityComparable& value);

   Wymagania: Typ T jest EqualityComparable.
   Efekt: Zwraca liczbę iteratorów i z przedziału [first, last), dla których
Algorytmy Non-mutating
 template<class InputIterator, class EqualityComparable>
  InputIterator find(InputIterator first, InputIterator last, const
  EqualityComparable& value)
  Wymagania: Typ T is EqualityComparable.
  Wynik: Pierwszy iterator i z przedziału [first, last), dla którego
  prawdziwy jest warunek: *i == value. Jeśli żaden iterator z tego
  przedziału nie spełnia tego warunku zwracany jest last.
 template<class InputIterator, class OutputIterator>
  OutputIterator copy(InputIterator first, InputIterator last, OutputIterator
  result);
  Efekt: kopiuje elementy z przedziału [first, last) do [result, result+(last-
  first)) zaczynając od first i kontynuując aż do last.
  Dla każdej nieujemnej liczby n < (last-first), wykonuje *(result+n) =
  *(first+n).
  Wynik: result + (last - first).
  Wymagania: result nie powinien być z przedziału [first, last).
  Złożoność: dokładnie last - first przypisań.
Przykład:
     template<class T> struct print : public unary_function<T, void>{
      print(ostream& out) : os(out), count(0) {}
      void operator() (T x) { os << x << ' '; ++count; }
      ostream& os;
      int count;
     };

     int main(){
      int A[] = {1, 4, 2, 8, 5, 7};
      const int N = sizeof(A) / sizeof(int);

         print<int> P = for_each(A, A + N, print<int>(cout));
         cout << endl << P.count << " objects printed." << endl;
     }
     Gdzie szukać informacji?

Musser Saini, STL Tutorial and Reference
 Lippman, "Istota jezyka C++„
N.M.Josuttis, C++ bibliotek standardowa
 podrecznik programisty
www-d0.fnal.gov/~dladams/cxx_standard.pdf
http://anubis.dkuug.dk/jtc1/sc22/open/n2356/
       Gdzie szukać informacji?

 http://www.sgi.com/tech/stl/ - implementacja STL firmy Silicon
  Graphics, Inc. (SGI)
 http://www.informatik.hs-bremen.de/~brey/stlbe.html - książka
  "Designing Components with the C++ STL"
 http://www.xraylith.wisc.edu/~khan/software/stl/STL.newbie.html
  - strona o STL z 1995 roku
 http://www.cs.brown.edu/people/jak/proglang/cpp/stltut/tut.html -
  prosty tutorial
 http://www.cs.rpi.edu/~wiseb/xrds/ovp2-3b.html - krótki opis STL'a
 http://pages.cpsc.ucalgary.ca/~kremer/STL/1024x768/index.html -
  strona o STL'u
Dziękuję za uwagę!