Programmieren in C++ Standardbibliothek (STL) Inhalt C++ Geschichte Standardbibliothek in der Übersicht Hilfsfunktionen und Hilfsklassen Relationale Operatoren Funktionales Programmieren Container Iteratoren Algorithmen Speicherverwaltung Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-2 C++: Die Anfänge 1979 • • „C with Classes“ wird von Bjarne Stroustrup in den AT&T Bell Laboratories entwickelt „C with Classes“ erweitert C um ein Klassenkonzept, welches sich an Simula-67 anlehnt 1983 • • Umbenennung in C++ viele Erweiterungen virtuelle Funktionen, Überladen von Funktionsnamen und Operatoren, Referenzen, Konstanten, änderbare Freispeicherverwaltung und eine verbesserte Typüberprüfung 1985 • 1. C++ Referenzversion (noch nicht standardisiert) 1989 • • 2. Version (noch nicht standardisiert) Erweiterungen Mehrfachvererbung, abstrakte Klassen, statische Elementfunktionen, konstante Elementfunktionen und die Erweiterung des Schutzmodells um protected Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-3 C++: Der Weg zum ISO/IEC Standard 1990-1998 • weitere Erweiterungen • • Templates, Ausnahmen, Namensräume, neuartige Typumwandlungen und boolesche Typen Erweiterung der C-Standardbibliothek um Datenströme und um die Standard Template Library (STL) Standardisierungsverfahren 1998 • Normung der endgültigen Fassung der Sprache C++ (ISO/IEC 14882:1998) 2003 • Nachbesserung der Norm von 1998 (ISO/IEC 14882:2003) 2005 • Technical Report 1 (TR1): Erweiterungen, die 2003 nicht standardisiert wurden 2011 • Einführung des neuen C++-Standards C++11 Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-4 C++ Standardbibliothek Erweiterbares Framework bestehend aus • • • • • • • • • • • Ausnahmebehandlung (Exceptions) Strings Container (numerische) Algorithmen komplexe Zahlen Anpassungen an nationale Zeichensätze Ein- und Ausgabe reguläre Ausdrücke Zufallszahlen und Wahrscheinlichkeitsverteilungen Threads und Synchronisationsprimitive … Grundlage und Dokumentation • • • Standard Template Library (STL) STL Programmierhandbuch von SGI C++ und STL Referenz Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-5 Schwerpunkte C++-Headers Hilfsfunktionen und -klassen <utility> <functional> Container <bitset> <deque> <forward_list> <list> <map> <queue> <set> <stack> <vector> Iteratoren <iterator> Algorithmen <algorithm> Ein- /Ausgabe <fstream> <iomanip> <ios> <iosfwd> <iostream> <istream> <ostream> <sstream> <streambuf> Numerisches <complex> <limits> <numerics> <valarray> Fehlerbehandlung <exception> <stdexcept> <system_error> String <string> Speicher <memory> <new> Laufzeittyperkennung <typeinfo> Nationale Zeichensätze <locale> Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-6 Schwerpunkte neue C++11-Headers Parallelität <thread> <future> Reguläre Ausdrücke <regex> Rechnen mit Einheiten <ratio> Rechnen mit Zeiteinheiten <clock> Wahrscheinlichkeitsverteilungen <random> Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-7 STL: Standard Template Library Entwicklung • • entwickelt von Alexander Stepanov et al. (1979-1994) bei HP basiert auf SGI's STL, ist aber nicht identisch Design-Regeln • • Polymorphismus zur Kompilationszeit (templates) STL-Container eignen sich schlecht als Basisklassen, weil die Destruktoren nicht virtual sind Bemerkung • • STL ist Teil der Standardbibliothek, der sich aber nicht mehr sauber vom Rest trennen lässt für C++11 komplett überarbeitet und erweitert worden Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-8 Hilfsfunktionen und Hilfsklassen Klasse tuple • erlaubt die Kombination heterogener Werte tuple<int, double, string> tup(1, 2.2, "drei"); auto val = get<0>(tup); get<1>(tup) = 1.5; size_t s = tuple_size<decltype(tup)>::value; // Anzahl Elemente im Tupel Funktion swap() • • vertauscht die Werte zweier Variablen vom gleichen Typ Originalcode template<class _Ty> inline void swap(_Ty& _Left, _Ty& _Right) { if (&_Left != &_Right) { _Ty _Tmp = _Left; _Left = _Right; _Right = _Tmp; } } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-9 Relationale Operatoren Voraussetzung für die Anwendung • die Klasse stellt die Operatoren == und < zur Verfügung Nutzen • • • • • die Realisierung der Operatoren a != b ! (a == b) a>b b<a a ≤ b ! (b < a) a ≥ b ! (a < b) Code-Ausschnitt namespace rel_ops { template<class T> bool operator!=(const T& x, const T& y) { return !(x == y); } } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-10 Funktionale Programmierung C++ ist ein Multi-Paradigmen-Sprache • • • imperatives Programmieren objektorientiertes Programmieren funktionales Programmieren Funktionale Programmierung • • • • Programme sind Funktionen Objekte sind unveränderlich (immutable) Funktionen produzieren neue Objekte Funktionen sind selber auch Objekte Funktionale Programmiersprachen • • • • LISP Haskell F# Scala Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-11 Funktionale Elemente von C++ Funktion • • • typisierte Parameterlisten variable Anzahl Parameter global oder als Methode einer (unveränderbaren) Klasse Funktor • Instanz einer Klassen, welche den Funktionsoperator operator()(…) überlädt Funktionszeiger (out in C++11) • Adresse auf eine Funktion Methodenzeiger • eine schon an eine Instanz gebundene Methode Lambda (C++11) • eine anonyme Funktion, ein so genannter Lambda-Ausdruck, welcher dort definiert werden kann (aber nicht muss), wo er eingesetzt wird Funktionsobjekt • Instanz der Klasse functional aus dem Header <functional> Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-12 Funktoren Objekte als Funktionen • • • die Aufgabe einer Funktion wird von einem Objekt übernommen Überladen des Funktionsoperators operator()(…) Anwenden des Funktionsoperators entspricht dem Aufrufen des Funktionsoperators für das entsprechende Objekt Beispiel enum Modus { Rad, Deg, Gon }; class Sinus { Modus m_mode; public: Sinus(Modus mode = Rad) : m_mode(mode) {} double operator()(double arg) { switch(m_mode) { case Rad: return sin(arg); case Deg: return sin(arg/180.0*M_PI); case Gon: return sin(arg/200.0*M_PI); } } }; Einsatz int main() { Sinus sinrad; Sinus sindeg(Deg); cout << sinrad(M_PI/4); cout << sindeg(45.0); } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-13 Lambda (C++11) Syntax • Zugriffsdeklaration Parameterliste [Rückgabetyp] Funktionskörper Beispiel • [bias] (int x, int y) -> int { return bias + x + y; } Zugriffsdeklaration • gibt in eckigen Klammern an, auf welche Variablen der Umgebung zugegriffen werden kann Parameterliste • Deklaration der Funktionsargumente analog zu normalen Funktionen Rückgabetyp • die Angabe des Rückgabetyps ist optional (kann vom Compiler selber ermittelt werden), darf auch void sein (Prozedur) Funktionskörper • ein gewöhnlicher Funktionskörper mit oder ohne return-Anweisung Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-14 Lambda Zugriffsdeklaration (C++11) Hintergrund • • • dort wo der Lambda-Ausdruck definiert wird, existiert eine lokale Umgebung bestehend aus lokalen Variablen und Instanzvariablen in der Zugriffsdeklaration wird angegeben, auf welche Variablen der Umgebung zugegriffen wird und ob der Zugriff by-value oder by-reference stattfinden soll auf statische und globale Variablen kann immer zugegriffen werden, auch ohne Angabe in der Zugriffsdeklaration Beispiele • • • • • • [bias] [&bias] [=] [&] [=, &bias] [factor, &bias] auf die Variable bias wird by-value zugegriffen auf die Variable bias wird by-reference zugegriffen auf alle Variablen der Umgebung wird by-value zugegriffen auf alle Variablen der Umgebung wird by-ref. zugegriffen nur auf bias wird by-ref. zugegriffen, sonst by-value auf factor wird by-value und auf bias by-ref. zugegriffen Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-15 Lambda hinter der Kulisse (C++11) void fLambda() { int notUsed = 3, byval = 4, byref = 5; auto op = [byval, &byref](int i) { ++byref; return i + byval + byref; }; cout << op(10) << endl; } void fFunctor() { int notUsed = 3, byval = 4, byref = 5; struct Op { int m_val; int& m_ref; Op(int val, int& ref) : m_val{val), m_ref{ref} {} int operator()(int i) const {++m_ref; return i + m_val + m_ref; } } op{byval, byref}; cout << op(10) << endl; } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-16 Funktionsobjekte im Einsatz (C++11) #include <functional> main() { function<float (float a, int x)> func; // Deklaration des Funktionsobjekts vector<int> v{1, 2, 3, 4, 5}; func = … // Definition des Funktionsobjekts // (Funktor, Funktionszeiger, Methodenzeiger, Lambda) // siehe nächste Folie // Einsatz des Funktionsobjekts in einem Algorithmus float r = accumulate(v.cbegin(), v.cend(), 1.0f, func); } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-17 Verschiedene Funktionsobjekte Funktor, Funktionszeiger Methodenzeiger, Lambda struct Funktor { float m_div; Funktor(float f) : m_div(f) {} float operator()(float a, int x) const { return a + x/m_div; } }; ---func = Funktor(2.0f); ---float foo(float a, int x) { return a + x/2.0f;} func = &foo; struct C { float m_div; C(float f) : m_div(f) {} float meth(float a, int x) const { return a + x/m_div; } }; ---C c(2.0f); func = bind(&C::meth, &c, _1, _2); ---func = [](float a, int x) { return a + x/2.0f; } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-18 Container (1) Bitvektoren fixer Länge • bitset: <bitset> Halbdynamische Container • vector und vector<bool>: <vector> Listen • • • double ended queue: <deque> list (doubly-linked): <list> forward_list (singly-linked, C++11): <forward_list> Geordnete Mengen • • set (die Schlüssel werden sortiert verwaltet): <set> multiset (Mehrfacheinträge sind erlaubt): <set> Geordnete Maps • • map: <map> multimap (Schlüssel müssen nicht eindeutig sein): <map> Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-19 Container (2) Ungeordnete Mengen (Hash-Sets, C++11) • • unordered_set (die Schlüssel werden sortiert verwaltet): <unordered_set> unordered_multiset (Mehrfacheinträge sind erlaubt): <unordered_set> Ungeordnete Maps (Hash-Maps, C++11) • • unordered_map: <unordered_map> unordered_multimap (Schlüssel müssen nicht eindeutig sein): <unordered_map> Container-Interfaces • • • verwendet einen Container (z.B., vector, deque oder list) als Datenbehälter bietet spezielle Datenzugriffe an Interfaces stack (LIFO): <stack> queue (FIFO): <queue> priority queue: <queue> Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-20 Container: Datentypen und Methoden Datentypen (angeboten/erforderlich) für Container X<T> • • • • • • • X::value_type X::reference X::const_reference X::iterator X::const_iterator X::difference_type X::size_type Container-Element, entspricht T Referenz auf Container-Element dito, aber nur lesend verwendbar Iterator dito, aber nur lesend verwendbar vorzeichenbehafteter integraler Typ vorzeichenloser integraler Typ für Grössenangaben Methoden (nicht vollständig) • • • • • • • Standard-, Kopier- und Verschiebekonstruktor, Destruktor Iteratoren (lesend und schreibend): begin() und end() Iteratoren (nur lesend): cbegin() und cend() Grössenangaben: max_size(), size(), empty() Zuweisungsoperator und Verschiebezuweisungsoperator Relationale Operatoren Vertauschen: swap(X&) Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-21 Iteratoren begin() Konzept • • • • • end() Iterator: verallgemeinerter Zeiger, welcher auf ein Element des Containers zeigt begin() und cbegin() liefern einen Zeiger, der aufs erste Element zeigt end() und cend() liefern einen Zeiger, auf ein fiktives Element unmittelbar nachfolgend dem letzten Element Inkrementierer ++ springt zum nächsten Element Dereferenzierer * ermöglicht Zugriff aufs Element Untypisches Beispiel template<class T> void printAll(const T& c) { T::const_iterator it = c.cbegin(), end = c.cend(); while(it != end) { cout << *it++ << ' '; } cout << endl; } vector<int> v(10); for(size_t i = 0; i < v.size(); i++) { v[i] = i; } printAll(v); Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-22 Freie Methoden begin() und end() Variante des gleichen Beispiels template<class T> void printAll(const T& c) { for(auto it = begin(c); it != end(c); ++it) { cout << *it << ' '; } cout << endl; } Verwendung des Range-For template<class T> void printAll(const T& c) { for(auto& val : c) { cout << val << ' '; } cout << endl; } Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-23 Iterator-Kategorien Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-24 Verschiedene Spezialiteratoren Move-Iteratoren • die Daten werden verschoben anstatt kopiert Insert-Iteratoren • • mit einem normalen Iterator kann auf Elemente lesend/schreibend zugegriffen werden ein Insert-Iterator erlaubt das einfügen in einen Container front_insert_iterator back_insert_iterator; Beispiel: back_insert_iterator<list<double>> bIt(l); insert_iterator (einfügen an spezifizierter Position) Reverse-Iteratoren • • läuft rückwärts von rbegin() bis rend() ++-Operator wird zum Iterieren verwendet Stream-Iteratoren Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-25 Algorithmen Grundsätze • • • • alle im Header <algorithm> vorhandenen Algorithmen sind unabhängig von einer konkreten Container-Implementierung enthält eine Container-Implementierung einen gleichnamigen Algorithmus wie im Header <algorithm>, so soll die spezielle Version des Containers verwendet werden (höhere Effizienz) die Algorithmen greifen über Iteratoren auf die Elemente des Containers zu wird ein First- und ein Last-Iterator verlangt, so ist damit das halboffene Intervall [First, Last) gemeint Beispiel vector<int>::iterator pos; pos = find_if(v.begin(), v.end(), bind2nd(equal_to<int>(), 25)); cout << *pos << endl; Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-26 Algorithmen: Übersicht (1) Suchen eines Elementes • • find, find_if, find_end, find_first_of, adjacent_find nth_element Suchen einer Sequenz • search, search_n Zählen von Elementen, die ein Prädikat erfüllen • count Vergleichen zweier Elemente • min, max, min_element, max_element Vergleichen zweier Sequenzen • lexicographical_compare Vergleichen zweier Container • mismatch, equal Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-27 Algorithmen: Übersicht (2) Kopieren der Elemente eine Quellbereichs in einen Zielbereich • copy, copy_backward Vertauschen von Elementen oder Containern • swap, iter_swap, swap_ranges Einfüllen von Sequenzen • fill, fill_n, generate, generate_n Ersetzen von Elementen • replace, replace_if, replace_copy, replace_copy_if Entfernen • • remove, remove_if, remove_copy, remove_copy_if unique, unique_copy Transformieren (Kopieren und dabei Modifizieren) • transform Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-28 Algorithmen: Übersicht (3) Reihenfolge verändern • • reverse, reverse_copy, rotate, rotate_copy, random_shuffle partition, sort, partial_sort Permutationen • prev_permutation, next_permutation Suchen in sortierten Sequenzen • • binary_search, lower_bound, upper_bound equal_range Mischen zweier sortierter Sequenzen • merge, inplace_merge Mengenoperationen auf sortierten Strukturen • includes, set_union, set_intersection, set_difference, set_symmetric_difference Heap-Algorithmen • pop_heap, push_heap, make_heap, sort_heap Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-29 Speichermanagement Header <new> • • • enthält die Operatoren new, new[], delete und delete[] Fehlerbehandlung bei der Speicherallokation: Verhinderung einer Exception bei der Speicherallokation std::bad_alloc Exception wird geworfen int *data = new(std::nothrow) data[1000]; Header <memory> • • • Speicherverwaltung erlaubt Erweiterung bzw. Anpassung der Standardspeicherverwaltung (z.B. durch Garbage Collection) Smart Pointers (unique_ptr, shared_ptr, weak_ptr) auto_ptr ist veraltet Prof. Dr. C. Stamm – Programmieren in C++, FS 13 10-30