003-Folien: Standard Template Library und Templates
003-Folien: Standard Template Library und Templates
003-Folien: Standard Template Library und Templates
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>Template</strong>s <strong>und</strong> STL<br />
VL MRT-2, SS 2013<br />
Professur für Prozessleittechnik
Übersicht<br />
• Neugestaltung des endlichen Zustandsautomaten mit<br />
Containern der <strong>Standard</strong> <strong>Template</strong> <strong>Library</strong> (statt Arrays)<br />
• C++ Konzepte:<br />
– Konzepte der <strong>Standard</strong> <strong>Template</strong> <strong>Library</strong><br />
– Eigene <strong>Template</strong>s erzeugen<br />
– Spezialisierung von <strong>Template</strong>s<br />
– Boost<br />
• Entwurfsmuster:<br />
– Container <strong>und</strong> Iteratoren<br />
24.04.2013 MRT2 (c) 2013, UR Folie 2
<strong>Standard</strong> <strong>Template</strong> <strong>Library</strong> (STL)<br />
• Ziele der STL:<br />
– Hohe Wiederverwendung von Datenstrukturen <strong>und</strong> typsicherer<br />
Algorithmen auf diesen Datenstrukturen<br />
• Problem:<br />
– Es gibt unendlich viele Datentypen (Classes)<br />
– Es gibt erstaunlich viele Möglichkeiten Sammlungen von Daten<br />
anzulegen (Collections)<br />
– Es gibt eine immense Vielfalt von Dingen die wir mit den Daten<br />
tun wollen (Algorithmen)<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 3
Beispiele für Algorithmen auf Sammlungen<br />
• Sortiere die Einträge eines Wörterbuchs<br />
• Suche die Telefonnummer zu einem Namen<br />
• Finde den höchsten Temperaturmesswert der vergangenen<br />
10 Jahre<br />
• Finde alle Werte > 8000<br />
• Finde die erste Instanz mit einem Wert von 17<br />
• Finde den ersten Unterschied in zwei Sequenzen<br />
• Berechne das paarweise Produkt der Elemente zweier<br />
Sequenzen<br />
• Berechne die Summe der Elemente<br />
• ...<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 4
Gr<strong>und</strong>legende Konzepte der STL<br />
• Container: Objekte zur Verwaltung anderer Objekte<br />
– abgelegt als Wert (Wertsemantik) oder als Referenz<br />
– formuliert als <strong>Template</strong>-Klassen<br />
– Algorithmennamen (werden zur Compilezeit ausgewertet) sind für<br />
gleichartige Operationen, aber unterschiedliche Container gleich.<br />
Beispiel: Die Methode size() gibt die Anzahl der Elemente eines<br />
Containers zurück, sei er nun vom Typ vector,list oder map).<br />
• Iteratoren: Zugriff auf Containerelement über Iteratoren<br />
– sind normale Zeiger oder zeigerähnliche Objekte<br />
– können sich von einem zum nächsten Element weiterbewegen, Methode<br />
bleibt aber verborgen<br />
– Beispiel: in einem Vektor: ++ das einfache Weiterschalten zur nächsten<br />
Position im Speicher; in einem binären Suchbaum: ++ Entlangwandern<br />
im Baum)<br />
• Algorithmen: arbeiten mit Iteratoren, die auf Container zugreifen<br />
– Allgemeinheit des Entwurfs, arbeiten auch mit normalen Zeigern<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 5
Wir nutzen in dem Automaten bereits<br />
Container <strong>und</strong> Iterator<br />
• Zeichenketten sind Containertemplates<br />
string f("--0002*30+-+1234=");<br />
• Klassisch: Iteration über C-String mit Zeiger (C):<br />
for (const char* cp = f.c_str(); *cp != 0; ++cp) { c =<br />
*cp; a.run(); }<br />
• STL-Iterator: Iteration über Container mit Iterator (C++):<br />
for (string::iterator it=f.begin(); it != f.end();<br />
++it) { c = *it; a.run(); }<br />
• Ab C++ C11: Iteration über Range<br />
for (const char cf : f) { c = cf; a.run(); }<br />
24.04.2013 MRT2 (c) 2013, UR Folie 6
Wichtige Klassen der STL<br />
• Sequenz-Container:<br />
– : basic_string, string, wstring - Zeichenketten<br />
– : deque – Liste mit zwei Enden<br />
• schnelles Anfügen von Elementen, kein wahlfreier Zugriff<br />
– : list<br />
• schnelles Anfügen von Elementen, kein wahlfreier Zugriff<br />
– : vector<br />
• schnelles Anfügen nur am Ende, wahlfreier Zugriff<br />
• Assoziative Container<br />
– : map, multimap<br />
• Paare von Schlüsseln. Einfügen, Löschen, Suchen O(log(N))<br />
– : set, multiset<br />
• Schlüssel. Komplexität wie map<br />
24.04.2013 MRT2 (c) 2013, UR Folie 7
Sequenz<br />
• Jede STL-Sammlung ist eine Sequenz<br />
– Eine Sequenz hat ein Anfang <strong>und</strong> ein Ende<br />
– Es gibt eine Möglichkeit vom Anfang zum Ende zu kommen<br />
– Anfang <strong>und</strong> Ende sind jeweils durch einen Iterator festgelegt.<br />
• Ein Iterator ist ein Objekt, das ein Element einer Sequenz<br />
identifiziert<br />
begin: end:<br />
...<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 8
Iterator<br />
• Ein Iterator „zeigt“ auf ein Element einer Sammlung (oder<br />
das nach dem letzten)<br />
• Iteratoren können verglichen werden (==)<br />
• Durch dreferenzieren bekommt man das Element, auf das<br />
der Iterator zeigt (*)<br />
• Der Iterator kann auf das nächste Element der Sammlung<br />
vorwärts bewegt werden (++)<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 9
Iteratoren verbinden<br />
• Iteratoren verbinden Datenstrukturen mit Algorithmen<br />
sort, find, search, copy, ...<br />
Iterator<br />
vector, list, map, array, ..., meinContainer<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 10
Automaton: TransitionTable als Container<br />
der STL<br />
• Anforderungen an die TransitionTable<br />
– Elemente: Zeiger auf konstante Transition-Objekte<br />
– Neue Elemente: am Ende anfügen<br />
– Durchsuchen: linear von Anfang bis Ende<br />
• list ist ein geeigneter Container<br />
für Zeiger auf unveränderliche Objekte<br />
vom Typ Transition:<br />
#include <br />
class Automaton {<br />
list tt;<br />
Automaton(const State& startState);<br />
void add(const Transition& t);<br />
...<br />
< Parameter >:<br />
Liste, deren<br />
Elemente Zeiger auf<br />
unveränderliche<br />
Transitionsobjekte<br />
sind<br />
Referenz auf ein<br />
unveränderliches<br />
Tranisitionsobjekt<br />
24.04.2013 MRT2 (c) 2013, UR Folie 11
Automaton: TransitionTable<br />
• Modifikation Automaton.h<br />
#include <br />
class Automaton {<br />
list tt;<br />
Automaton(const State& startState);<br />
void add(const Transition& t);<br />
• Modifikation Implementierung<br />
Automaton::add(const Transition& t) {<br />
tt.push_back(&t); }<br />
Automaton::run() { // [...]<br />
for (const Transition* pt : tt) {<br />
if ( &(pt->start) == pCurrentState ) {<br />
Referenz wird wie<br />
Variable behandelt,<br />
deshalb Adresse<br />
bestimmen<br />
push_back: Element<br />
an Container<br />
anhängen<br />
Über alle Elemente<br />
der Liste<br />
24.04.2013 MRT2 (c) 2013, UR Folie 12
STL: Übersicht Container-Methoden<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 13
Initialisierung TransitionTable<br />
• Objektinitialisierung<br />
Automaton a(s0);<br />
a.add(Transition(s0, s0, guardPlus));<br />
a.add(Transition(s0, s1, guardMinus, behavior_lOp_Sign));<br />
a.add(Transition(s0, s2, guardDigit, behavior_lOp_Digit));<br />
a.add(Transition(s1, s0, guardMinus, behavior_lOp_Sign));<br />
a.add(Transition(s1, s2, guardDigit, behavior_lOp_Digit));<br />
a.add(Transition(s2, s2, guardDigit, behavior_lOp_Digit));<br />
a.add(Transition(s2, s3, guardOp, behavior_Op1));<br />
// ...<br />
24.04.2013 MRT2 (c) 2013, UR Folie 14
C++: <strong>Template</strong>s - Motivation<br />
• Für alle Typen, für die die Relation < definiert ist, kann eine<br />
min bzw. max-Funktion spezifiziert werden.<br />
• Das ist mit Überladen von Funktionen in C++ gr<strong>und</strong>sätzlich<br />
lösbar:<br />
string& min(string& a, string& b) {<br />
return (a < b) ? a : b;<br />
}<br />
double& min(double& a, double& b) {<br />
}<br />
return (a < b) ? a : b;<br />
• u.s.w für alle Datentypen, für die bool T& operator
C++: Funktionstemplates<br />
string& min(string& a,<br />
string& b)<br />
{<br />
}<br />
return (a < b) ? a : b;<br />
double& min(double& a,<br />
double& b)<br />
{<br />
return (a < b) ? a : b;<br />
}<br />
• Funktionstemplate =<br />
typunabhängige Formel<br />
• Aus der Formel erzeugt der<br />
Compiler typspezifische<br />
Versionen (wenn benötigt)!<br />
template <br />
T& min(T& a, T& b)<br />
{<br />
}<br />
Parameterliste des<br />
<strong>Template</strong>s<br />
return (a < b) ? a : b;<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 16
C++: <strong>Template</strong>parameterliste (1/2)<br />
• Zur Erinnerung: Funktionsparameterliste<br />
– Definiert lokale Variablen eines bestimmten Typs<br />
– Variablen werden nicht initialisiert<br />
– Belegung zur Laufzeit bei Aufruf<br />
• <strong>Template</strong>parameterliste<br />
– Liefert Typen oder Werte, die bei der Definition der Funktion<br />
oder Klasse verwendet werden können:<br />
template T& min(T& a, T& b);<br />
– Die Verwendung im Programm bestimmt, welcher Typ mit T<br />
gemeint ist.<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 17
C++: <strong>Template</strong>parameterliste (2)<br />
• Typparameter<br />
– Repräsentation eines zur Zeit der Programmierung<br />
unbekannten Datentypy<br />
– Eingeleitet durch Schlüsselwort typename oder class<br />
• Nichttypparameter<br />
– Repräsentation eines zur Zeit der Programmierung<br />
unbekannten Werts<br />
– Eingeleitet durch Typspezifizierer, z.B. int, size_t<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 18
C++: Regeln für <strong>Template</strong>parameter<br />
• Gültigkeitsbereich folgt den normalen Regeln des<br />
Versteckens von Namen<br />
typedef double T;<br />
template <br />
T& min(T& a, T& b)<br />
{<br />
}<br />
T tmp = a;<br />
return (a < b) ? a : b;<br />
Das globale typedef von T als<br />
double wird durch den<br />
Typparameter T versteckt.<br />
• Ein Name der als <strong>Template</strong>parameter benutzt wird, darf<br />
innerhalb des <strong>Template</strong>s nicht für etwas anderes benutzt<br />
werden!<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 19
C++: <strong>Template</strong>deklaration<br />
• <strong>Template</strong>s können wie Klassen oder Funktionen auch nur<br />
deklariert werden<br />
template T &min(T &a, T &b);<br />
• In der Definition muss der Name des <strong>Template</strong>parameters<br />
nicht gleich sein!<br />
template U &min(U &a, U &b) { /**/ };<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 20
Anwendung Automaton<br />
• Problembeschreibung: State <strong>und</strong> Transition sind<br />
zugeschnitten auf Verhaltensspezifikationen vom Typ<br />
typedef function Behavior;<br />
• Herausforderung: Beschreibung der Klassen als <strong>Template</strong>,<br />
damit der Compiler typsicheren Code für<br />
Strategiefunktionen erzeugt, beispielsweise zur Übergabe<br />
von const char, int, container, shared memory...<br />
State s0("s0",...);<br />
Automaton a(s0);<br />
TU Dresden, 21.04.13 MRT2 2006-2011 (c) UR Folie 21
Vorbereitung (1/3) CalcAsFSM<br />
• Schritt 1: Die ad-hoc Realisierung des Speichers als globale<br />
Variablen <strong>und</strong> Funktionen war keine gute Praxis<br />
• Kapseln in Klasse Calc<br />
typedef char const cc;<br />
class Calc {<br />
// rechter Operand - Wert <strong>und</strong> Vorzeichen<br />
int rOp;<br />
int rSign;<br />
// ...<br />
Das wird später<br />
unser <strong>Template</strong>parameter!<br />
void behavior_rOp_Digit(const AutomatonElement& ae, cc& c) {<br />
rOp = rOp * 10 + c - '0';<br />
}<br />
24.04.2013 MRT2 (c) 2013, UR Folie 22
Vorbereitung (2/3) Automaton<br />
• Schritt 2: Verwendung von std::function in Automaton für<br />
die vereinheitlichte Behandlung von Methoden <strong>und</strong><br />
Funktionen<br />
• Behavior.h<br />
#include <br />
using namespace std;<br />
Rückgabewert<br />
Argumentliste<br />
// Typdefinition für<br />
typedef std::function Behavior;<br />
void defaultBehavior(const AutomatonElement&, const char&);<br />
// default behavior<br />
24.04.2013 MRT2 (c) 2013, UR Folie 23
Vorbereitung (3/3) CalcAsFSM<br />
• Schritt 3: Definition der Strategy durch Binden der<br />
Methoden der Klasse Calc an das Object<br />
calc<br />
#include <br />
using namespace std;<br />
using namespace std::placeholders;<br />
int main() {<br />
// ...<br />
Calc calc();<br />
// ...<br />
State s0("0",<br />
defaultBehavior,<br />
defaultBehavior,<br />
std::bind(&Calc::behavior_logState,&calc,_1,_2);<br />
Binden der Argumente<br />
std::placeholders::_1,<br />
std::placeholders::_2,<br />
std::function auch für<br />
Funktionszeiger<br />
Methode<br />
Instanzreferenz<br />
Argumentliste ermöglicht<br />
Umsortieren, Variablen<br />
24.04.2013 MRT2 (c) 2013, UR Folie 24
<strong>Template</strong>s für leere Verhaltensfunktionen<br />
(Behavior.h, AutomatonElement.h)<br />
• <strong>Template</strong>-Typdefinition für Behavior (leider erst ab C++11)<br />
template <br />
using Behavior = std::function<<br />
void(constAutomatonElement&, T&)>;<br />
( Bis dahin jeweils lokal in den Klassen zu definieren)<br />
• Verhaltensspezifikationen für „Nichts Tun“<br />
template <br />
void defaultBehavior(const AutomatonElement& ae, T&<br />
arg) {<br />
#ifdef DEBUG<br />
clog
Klassentemplate für State<br />
(analog für Transition)<br />
template <br />
class State: public AutomatonElement {<br />
typedef std::function Behavior;<br />
private:<br />
Behavior enterFunc;<br />
public:<br />
State(const string& id, Behavior enterFunc =<br />
defaultBehavior, [...]) :<br />
AutomatonElement(id), enterFunc(enterFunc), [...] { }<br />
inline void enter(T& arg) const {<br />
enterFunc(*this, arg);<br />
private:<br />
static const string myType;<br />
}<br />
template <br />
const string State::myType = "state";<br />
<strong>Template</strong>parameter<br />
T<br />
Wird bei lokaler<br />
Typdefinition des<br />
Funktionszeigers<br />
eingesetzt!<br />
Nachgestellt:<br />
Direkte<br />
Spezifikation der<br />
Funktion ohne<br />
Argumentliste!<br />
Alle Methoden die<br />
T verwenden!<br />
Implementierungen<br />
müssen auch als<br />
<strong>Template</strong> formuliert<br />
werden<br />
24.04.2013 MRT2 (c) 2013, UR Folie 26
Klassentemplate für Automaton<br />
template <br />
class Automaton {<br />
private:<br />
State const * pCurrentState;<br />
list< Transition const * > tt;<br />
int currentStateTicks;<br />
bool first;<br />
public:<br />
};<br />
Automaton(State const & startState);<br />
~Automaton();<br />
void add(Transition const & t);<br />
void run(T& arg);<br />
Bei allen betroffene<br />
Datentypen<br />
„durchziehen“<br />
Ein geschachteltes<br />
<strong>Template</strong>!<br />
24.04.2013 MRT2 (c) 2013, UR Folie 27
Implementierungen (1/3)<br />
template <br />
Automaton::Automaton(State const & startState) :<br />
pCurrentState(&startState), currentStateTicks(0),<br />
first(true) { }<br />
template <br />
void Automaton::add(Transition const & t) {<br />
}<br />
tt.push_back(new Transition(t));<br />
template <br />
Automaton::~Automaton() {<br />
}<br />
for (typename list::iterator it=tt.begin();<br />
it != tt.end(); ++it) delete (*it);<br />
tt.clear(); // eventually clear tt<br />
Implementierungen<br />
sind ebenfalls<br />
<strong>Template</strong>s<br />
Lege Zeiger auf<br />
eine dynamisch<br />
erzeugte Kopie in<br />
der Sammlung ab<br />
Alles was mit new<br />
angelegt wurde<br />
muss selbst mit<br />
delete aufgeräumt<br />
werden !!!!<br />
24.04.2013 MRT2 (c) 2013, UR Folie 28
Implementierungen (2/3)<br />
template <br />
Automaton::Automaton(State const & startState) :<br />
pCurrentState(&startState), currentStateTicks(0),<br />
first(true) { }<br />
template <br />
void Automaton::add(Transition const & t) {<br />
}<br />
tt.push_back(new Transition(t));<br />
template <br />
Automaton::~Automaton() {<br />
}<br />
for (typename list::iterator it=tt.begin();<br />
it != tt.end(); ++it) delete (*it);<br />
tt.clear(); // eventually clear tt<br />
Hier benötigt der<br />
Compiler unsere<br />
Hilfe: er kann nicht<br />
selbst entscheiden<br />
ob er einen Typ<br />
oder eine Instanz<br />
anlegen soll.<br />
24.04.2013 MRT2 (c) 2013, UR Folie 29