Transcript ppt

KURS JĘZYKA C++
– WYKŁAD 13 (19.05.2014)
Narzędzia programistyczne w bibliotece
standardowej
SPIS TREŚCI
Standardowa biblioteka wzorców STL
 Pary i tuple
 Sprytne wskaźniki
 Ograniczenia liczbowe
 Minimum i maksimum
 Zamiana zawartości obiektów
 Operatory porównywania
 Współczynniki
 Pomiar czasu
 Funkcje lambda

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:








strumienie we/wy,
kontenery, iteratory,
algorytmy, obiekty funkcyjne,
łańcuchy,
wyrażenia regularne,
wielowątkowość i przetwarzanie współbieżne,
internacjonalizacja,
klasy narzędziowe.
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 (typy danych są
rozpoznawane przez kompilator po typach argumentów).
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.
PARY – PRZYKŁADY
void f(std::pair<int, const char*>);
void g(std::pair<const int, std::string>);
...
std::pair<int, const char*> p(46,"hello");
f(p); // OK:
// calls implicitly generated copy constructor
g(p); // OK:
// calls template constructor
TUPLE








W C++11 zdefiniowano tuple do przechowywania wielu wartości a nie tylko
dwóch (szablon tuple<> jest analogią do szblony pary pair<>).
Tupla posiada wiele ponumerowanych pól, do których dostęp mamy za pomocą
metody get<i>.
Tupla posiada konstruktor wieloargumentowy oraz domyślny i kopiujący.
Tuple można porównywać za pomocą operatorów porównań (porównywanie
leksykograficzne).
Istnieje szablon funkcji make_tuple() do tworzenia tupli (typy danych są
rozpoznawane przez kompilator po typach argumentów).
Istnieje szablon funkcji tie() do tworzenia tupli z referencjami (jako
argumenty podaje się zmienne).
Szablon tuple_size<tupletype>::value służy do podania liczby
elementów w tupli.
Szablon tuple_element<idx,tupletype>::type służy do podania
typu elementu o indeksie idx w tupli.
TUPLE – PRZYKŁADY
// create a four-element tuple
// - elements are initialized with default value
tuple<string,int,int,complex<double>> t;
// create and initialize a tuple explicitly
tuple<int,float,string> t1(41,6.3,"nico");
// ‘‘iterate’’ over elements:
cout << get<0>(t1) << " ";
cout << get<1>(t1) << " ";
cout << get<2>(t1) << " ";
cout << endl;
TUPLE – PRZYKŁADY
// create tuple with make_tuple()
// - auto declares t2 with type of right-hand side
auto t2 = make_tuple(22,44,"nico");
// assign second value in t2 to t1
get<1>(t1) = get<1>(t2);
// comparison and assignment
// - including type conversion
if (t1 < t2) { // compares value for value
t1 = t2; // OK, assigns value for value
}
SPRYTNE WSKAŹNIKI






Sprytne wskaźniki są zdefiniowane w pliku nagłówkowym <memory>.
Sprytne wskaźniki maksymalnie naśladują zwykłe wskaźniki.
Sprytne wskaźniki wspierają technikę zdobywania zasobów poprzez
inicjalizację.
Wskaźnik shared_pointer<> jest wskaźnikiem ze zliczaniem referencji –
współdzielony wskaźnik automatycznie niszczy swoją zawartość, jeśli nie ma
już współdzielonych wskaźników odnoszących się do obiektu początkowo
tworzonego dla współdzielonego wskaźnika.
Słaby wskaźnik weak_ptr<> jest referencją do wskaźnika
shared_ptr<>, która może określać, czy wskaźnik shared_ptr<> był
kasowany czy też nie – sam weak_ptr<> nie ma na celu zachowywanie się
jak zwykły wskaźnik C++; po prostu jest obiektem i dostęp do faktycznego
wskaźnika wymaga stworzenia obiektu shared_ptr<>.
Wskaźnik unique_ptr<> jest zamiennikiem przestarzałego auto_ptr<>
– ma wszystkie możliwości auto_ptr<> z wyjątkiem niebezpiecznego
niejawnego przenoszenia z l-wartości; wskaźnik unique_ptr<> może być
stosowany z kontenerami C++11 uwzględniającymi przenoszenie.
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 T &b)
{ return b<a ? b : a; }
template <class T>
inline const T& max (const T &a, const T &b)
{ return a<b ? b : a; }
Istnieją też wersje tych szablonów z komparatorami (funkcja lub obiekt
funkcyjny):
template <class T, class C>
inline const T& min (const T &a, const T &b, C comp)
{ return comp(b,a) ? b : a; }
template <class T>
inline const T& max (const T &a, const T &b, C comp)
{ return comp(a,b) ? b : a; }
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
MINIMUM I MAKSIMUM



Funkcja minmax()zwraca parę elementów pair<>, gdzie pierwszy element
jest minimum a drugi maksimum.
Argumentem funkcji minmax()są dwa elementy albo lista elementów;
ostatnim argumentem może być metoda porównująca.
Przykład:
bool int_ptr_less (int* a, int* b) { return *a < *b; }
int x = 17, *px = &x;
int y = 42, *py = &y;
int z = 33, *pz = &z;
...
std::pair<int*, int*> extremes =
std::minmax ({px, py, pz}, int_ptr_less);
// auto extremes =
//
std::minmax ({px, py, pz},
//
[](int*a, int*b) { return *a < *b; });
ZAMIANA ZAWARTOŚCI OBIEKTÓW



Zamiana dwóch wartości:
template <typename T>
inline void swap (T &a, T &b)
{ T tmp(a); a = b; b = tmp; }
Można też zamieniać ze sobą tablice o określonej liczbie elementów:
template <typename T, size_t N>
void swap (T (&a)[N], T (&b)[N])
noexcept(noexcept(swap(*a, *b)));
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) { … }
…
}
WSPÓŁCZYNNIKI



W pliku nagłówkowym <ratio> jest zdefiniowany szablon
do tworzenia współczynników.
Definicja tego szablonu przypomina liczbę wymierną:
template <intmax_t N, intmax_t D = 1>
class ratio {
public:
typedef ratio<num,den> type;
static constexpr intmax_t num;
static constexpr intmax_t den;
//…
};
Licznik num i mianownik den są automatycznie redukowane
do minimalnych wartości (mianownik będzie dodatni).
WSPÓŁCZYNNIKI – PRZYKŁADY
typedef ratio<25,15> FiveThirds;
cout << FiveThirds::num << "/"
<< FiveThirds::den << endl;
// 5/3
ratio<42,42> one;
cout << one.num << "/" << one.den << endl;
// 1/1
ratio<0> zero;
cout << zero.num << "/" << zero.den << endl;
// 0/1
typedef ratio<7,-3> Neg;
cout << Neg::num << "/" << Neg::den << endl;
// -7/3
WSPÓŁCZYNNIKI
Obliczenia na współczynnikach można wykonywać w trakcie
kompilacji za pomocą następujących szablonów: ratio_add,
ratio_subtract, ratio_multiply i ratio_divide
(operacje arytmetyczne) oraz ratio_equal,
ratio_not_equal, ratio_less, ratio_less_equal,
ratio_greater i ratio_greater_equal (porównania).
 Przykład:
ratio_add<ratio<2,7>,ratio<2,6>>::type
ratio_equal<ratio<5,3>,ratio<25,15>>::value
 Istnieje też wiele predefiniowanych jednostek ratio<>:
pico, nano, micro, milli, centi, deci, deca, hecto,
kilo, mega, giga, tera…

POMIAR CZASU
Biblioteka standardowa wprowadza narzędzia pomocne do
pomiaru czasu – są one zdefiniowane w pliku nagłówkowym
<chrono> w przestrzeni nazw std::chrono.
 Podstawowe pojęcia: punkt czasowy (ang. timepoint), przedział
czasowy (ang. duration), epoka – punkt bieżący zegara (ang.
epoch).

POMIAR CZASU


Przedział czasowy reprezentowany przez szablon
std::chrono::duration<> jest liczbą określonych jednostek
czasowych (mierzonych w sekundach).
Przykłady:
std::chrono::duration<int>
twentySeconds(20);
std::chrono::duration<double,std::ratio<60>>
halfAMinute(0.5);
std::chrono::duration<long,std::ratio<1,1000>>
oneMillisecond(1);

W bibliotece standardowej zdefiniowano następujące typy przedziałów
czasowych: nanoseconds, microseconds, milliseconds,
seconds, minutes i hours.

Przykłady:
std::chrono::seconds twentySeconds(20);
std::chrono::hours aDay(24);
POMIAR CZASU
Przedziały czasowe możemy porównywać, dodawać,
odejmować, mnożyć i dzielić przez współczynniki oraz
inkrementować i dekrementować o określoną jednostkę.
 Przykład:
chrono::duration<int,ratio<1,3>> d1(1);
// 1/3 sekundy
chrono::duration<int,ratio<1,5>> d2(1);
// 1/5 sekundy
d1 + d2 /* 8 jednostek z 1/15 sekundy */
d1 < d2 /* false */

POMIAR CZASU




Zegar definiuje epokę i długość tyknięcia zegara.
W bibliotece standardowej zdefiniowane są trzy zegary:
system_clock (z funkcjami to_time_t() oraz
from_time_t()), steady_clock (nigdy nie korygowany) i
high_resolution_clock (dokładny zegar systemowy).
Bieżący czas można uzyskać za pomocą metody now():
auto system_start = chrono::system_clock::now();
Sprawdzenie czy upłynęła co najmniej minuta do startu:
if (system_clock::now() > system_start +
minutes(1))
POMIAR CZASU

Punkt czasowy jest reprezentowany przez obiekt time_point.

Pomiaru czasu można dokonać za pomocą punktów czasowych:
auto t = steady_clock::now();
// ... do something ...
auto d = steady_clock::now()−t;

Konwersja punktu czasowego do postaci kalendarzowej:
std::string asString
(const std::chrono::system_clock::time_point &tp) {
// convert to system time:
std::time_t t =
std::chrono::system_clock::to_time_t(tp);
std::string ts =
std::ctime(&t); // convert to calendar time
ts.resize(ts.size()-1); // skip trailing newline
return ts;
}
FUNKCJE LAMBDA
Programista często chciałby zdefiniować predykatowe funkcje
w pobliżu wywołań takich funkcji, jak na przykład
pochodzących ze standardowej biblioteki <algorithm>
(szczególnie sort i find) – oczywistym rozwiązaniem jest
zdefiniowanie w takim miejscu funkcji lambda (określanej też
jako lambda-wyrażenie).
 Funkcje lambda to anonimowe obiekty funkcyjne.
 Główne zastosowanie funkcji lambda to ich użycie jako
argumentu sterującego obliczeniami w innych funkcjach.
 Przykład:
[](int x, int y) { return x + y; }

FUNKCJE LAMBDA
Funkcja lambda określa typ zwracanego wyniku za pomocą
frazy -> TYP.
 Przykład:
[](int x, int y) -> int
{ int z = x * x; return z + y + 1; }
 Jeśli ciało funkcji lambda składa się z jednej instrukcji return,
to typ zwracanego wyniku będzie wydedukowany za pomocą
decltype().
 Przykład:
[](int x, int y) // -> decltype(x*x+y+1)
{ return x * x + y + 1; }

FUNKCJE LAMBDA

…