Haladó C++ Programozás Az STL sablonkönyvtár felhasználói szemszögből 2013. október
Mai témák STL bevezető adattároló struktúrák (konténerek) egyelőre csak alaptípusokkal léptetők (iterátorok) algoritmusok STL
STL sablonkönyvtár STL Szóismétlés, hiszen Mi van benne? S: Standard =Szabvány(os(ított)) T: Template =Sablon L: Library =Könyvtár (Gyűjtemény) Mi van benne? adattárolási struktúrák (konténerek) műveletsablonok (minus, plus, …) mert a globális operátorokat nem lehet örökíteni alapértelmezett viselkedés: rendes operátorokat hívja meg (+,-,<,=,*) algoritmusok konténerekre (bepakol, kiszed, rendez, keres, feje tetejére állít, …) segédanyagok (adatelérésre, memóriakezelésre) Mi nincs benne? teljes egyetértés SGI vs. Microsoft, etc. van, ami csak ajánlás, de nem kötelező implementálni fordítási hibaüzenetekhez értelmezőszótár meg kell tanulni a többsoros hibaüzenetekből a lényeget kiolvasni Van hozzá nagyon jó dokumentáció (http://www.sgi.com/tech/stl) Elterjedettsége nagyfokú dinamikus adatkezelést lebonyolító eljárás ma gyakorlatilag ritkaság nélküle (és értelmetlen is) STL
STL - koncepció Duális világ: keret (váz) + anyag (esszencia) pl.: (nem lesz számonkérve, de segít megérteni) pl.: Ember Test Értelem Csont Hús Lélek Szellem nem testi.. attitűd fantázia STL
avagy... ez témájában jó példa, mert a nyelvről szól kijelentés alany állítmány bővítmények... ez témájában jó példa, mert a nyelvről szól C++ is egy nyelv... STL
tervezési minták (design patterns) – félév 3. része Ami pedig minket illet program kód adat kódsablon egyedi kód adatstuktúra egyedi adat tervezési minták (design patterns) – félév 3. része STL, főleg a konténerek, de tágabb körben a hozzájuk szorosan kapcsolódó algoritmusok is adat – kód szétválasztás megvan architekturálisan is, már az XT-ben is... Ezzel már tényleg lehet komoly kód- újrahasznosítást művelni! STL
Coming soon: vector<T> vector<int> a(10); 10 hosszú int tömb for (int i=0;i<10;++i) a[i]=2*i; op[]-ral indexelt direkt elemelérés nemcsak olvasásra, hanem írásra is! a.resize(15); dinamikus átméretezés a.push_back(4); elem hozzátoldása a végéhez cout<<a.size(); méret lekérdezése (belsőleg tárolja, ellentétben int *a=new int[x]-szel) stb. olvasd: kocka operátorral (vagy operátor szögletes zárójellel) STL
Adattárolási struktúrák Elvárások a konténerrel szemben Transzparens működés memóriakezelés szempontjából (new – delete elrejtése, memóriaszivárgás kiküszöbölése) dinamikus nyújtózkodás esetén másoláskor születésnél/elhaláskor Jellemzők lekérdezése méret (elemszám) legkisebb/legnagyobb elem melyik elemből mennyi van STL
Adattárolási struktúrák Elvárások a konténerrel szemben Elemek közvetlen elérése Adatbeszúrás/-módosítás/-törlés Halmaz- és egyéb algoritmusok támogatása (az “elvárás” alatt azt is értsd, hogy a nagyHF- ben elvárjuk) STL
Konténerek Legjellemzőbb felosztás: Szekvenciális szerkezetek a felhasználó határozza meg az elemek sorrendjét vector dinamikus méretű, közvetlen elérésű tömb list kétirányba láncolt lista deque előre-hátra dinamikusan nyújtózkodó k.e. tömb Asszociatív szerkezetek ő magának sorrendezi az elemeket, hogy hatékonyan tudja majd kezelni őket set rendezett halmaz map rendezett asszociatív tömb multiset elemismétlődést megengedő rend. halmaz multimap 1:N leképezést megengedő asszoc. tömb STL
Konténerek Egyéb szerkezetek Megjegyzés: hash ~_map ~_set ~_multimap gyorsabb asszociáció, de nem egységes szabvány, ezért soruljuk az egyéb szerkezetek közé ~_map ~_set ~_multimap ~_multiset Megjegyzés: Java-ban szabványos a hash* tárolási struktúra, ott gyakrabban használjuk, C++ map<> pedig a java TreeMap<>-jához hasonlít. STL
Konténerek Egyéb szerkezetek Megjegyzés: hash ~_map ~_set ~_multimap gyorsabb asszociáció, de nem egységes szabvány, ezért soruljuk az egyéb szerkezetek közé ~_map ~_set ~_multimap ~_multiset Megjegyzés: Java-ban szabványos a hash* tárolási struktúra, ott gyakrabban használjuk, C++ map<> pedig a java TreeMap<>-jához hasonlít. STL
Konténerek Speciális szerkezetek slist egy irányba láncolt lista bit_vector bool értékek tárolására rope szövegeknek stack verem heap kupac queue FIFO szerkezet bitset<int> meghatározott bitszámú adatoknak karakterláncok bizonyos műveletek gyakoriabbak, célorientált optimalizálás Karakterláncokra miért készítettek sablont, miért nem csak char típusra definiálták? STL
Konténerek Speciális szerkezetek++ Régebbi NagyHF-k tömörítő konténer log-olás dupla indexelésű asszociáció (mikor-hol mi a helyzet, ~www.idokep.hu) oda-vissza asszociáció kétnyelvű szótár egyéb lehetőségek... cache-elt elérés a leggyakrabban használt adatokra unpop művelet támogatása stb. STL
Konténerek Speciális szerkezetek++ Újabb NagyHF-k Mátrix “flat” tárolási struktúra Beszúrás, törlés, módosítás Oszlopra, sorra, elemre Transformáció Transzponálás Aritmetika Összeadás, szorzás Determináns Inverz Asszociatív mátrix Mátrix tárolási struktúrát adottnak véli Asszociatív címzés sorra, oszlopra STL
A vector és a lista A vector<T> T dinamikus tömbjét valósítja meg. Az elemek közvetlen egymás után, egy tömbben vannak a memóriában. Elemeket el lehet érni tömbindexeléssel, működik a pointer-aritmetika. A túlindexelés (tömb méretén felüli elem írása/olvasása) nem definiált hatást eredményez. vector1_demo.cc vector2_demo.cc kiírórutin ostream &operator<<(ostream&, const X&) elterjedt használata, később is.. STL
A vector és a lista A list<T> két irányba láncolt T listát valósít meg list1_demo.cc mindkét irányban egyszerűen bővíthető/törölhető, sőt elembeszúrás is O(c) idő alatt zajlik le nincs közvetlen elérés: indexelés nincs rá értelmezve, helyette iterátorral lehet benne lépkedni list2_demo.cc beépített algoritmusok list3_demo.cc feltuningolt pointer STL
A vector és a lista ? ! Value_n+1 vector push_back() Value0 Value1 operator[ ](0) operator[ ](2) operator[ ](1) Value0 Value1 Value2 Value_n X pszeudo-iterator, vagyis nincs alatta érték, az opetator++() nem ad értelmes választ, de arra jó, hogy az end()-del összehasonlítsuk ? Hol van a vector esetén az iterátor? ! Az értékre mutató pointer az iterátor. list end() begin() operator++() operator++() operator++() Iterator1 Iterator2 Iterator3 IteratorN X operator--() operator*() operator*() operator*() Value1 Value2 Value3 X STL
vector vs. list elem elérése beszúrás attól függ, hova: deque elem elérése beszúrás attól függ, hova: előre középre végére objektumok összefűzése, intervallumok manipulálása (insert(), erase(), copy() etc.) O(n) O(c) STL
coming soon: map<K,V> map<TimeStamp, double> laz; időpontokhoz rendelünk double értékeket laz[TimeStamp(06,30)]=37.1; laz[TimeStamp(10,05)]=37.5; laz.insert(pair<TimeStamp,double>(TimeStamp(09,20),37.6)); elemek beszúrása laz[TimeStamp(06,30)]=36.9; elem felülírása double x=laz[TimeStamp(10,05)]; érték kiolvasása double y=laz[TimeStamp(00,00)]; nem definiált kulcs alól default érték kiolvasása (+ beszúrása!) map<TimeStamp,double>::iterator laz_0735it=laz.find(TimeStamp(07,35)); keresés kulcs szerint if (laz_0735it!=laz.end()) pair<TimeStamp,double> laz_0735=*laz_0735it; iterátor alatt kulcs-érték pár map<TimeStamp,double>::iterator laz_reggelit=laz.lower_bound(TimeStamp(08,00)); nem pontos, de közeli (megadottnál nagyobb kulcsú) elem keresése STL
Rendezett asszociatív tárolóstruktúrák (előzetes összefoglaló) Ide tartozik map, multimap, set, multiset Erősség bizonyos algoritmusok támogatása rendezettségből adódóan a keresés O(log(n)) egyediség alapértelmezetten garantált (map, set esetében) Hogyan biztosítjuk a rugalmasságot elemeire iterátorok mutatnak (akárcsak vector, list esetében) rendezés szabálya megadható függvényosztállyal, azaz funktorral általános elérési felület (interface) begin(), end(), empty(), insert()-ek, clear(), konstruktor intervallummal külső függvényekre iterátorokkal kell illeszteni mindegyik konténert mint intervallumot STL
-torok latin magyarul igék: fungor,fungi,functus végrehajt, cselekszik itero,iterare,iteravi,iteratus ismétel, hajtogat (szavakat, nem origamit) képzők (igék negyedik (passzív) alakjából): -tus/-sus → -tor/-sor cselekvő alany (ld. még: diktátor) -tus/-sus → -tion/-sion szenvedő alany magyarul functor végrehajtó iterator ismétlő STL
Kapcsolódás egymáshoz? -torok rendez: < összegez: + keres: <,= léptet: ++,-- C++ Algoritmusok Műveletek funktorok iterátorok Kapcsolódás egymáshoz? másol, töröl, keres, rendez, összegez, …léptet… Beépített algoritmusok Konténer STL
Functor (function object) olyan objektum, ami függvényként használható mert rendelkezik publikus operator()-ral (zárójel operátorral) haszna: egzakt típus örököltethető, stb ahová a kód egy fv.-t vár, oda beilleszthető mi közünk hozzá? STL épít rá rendezési reláció, transzformáló rutin, konténerhez feltöltőrutin... amúgy is ritkán használt szabványos nyelvi elem, tehát a HCPP kurzusnak tárgya STL
Functor mint rendezési reláció A példák egymásra épülnek, bemutatják a funktor erejét: functor1.cc functor2.cc functor3.cc functor4.cc functor5.cc Tehát az ereje: képes függvényként működni inicializálható lehet belső memóriája STL
Iterátorok “objektummá felturbózott pointer” Mire használjuk őket? de mint láttuk, olykor a pointer is lehet iterátor (pl. vector vagy hagyományos tömb esetén) Miért? Mert template programozás esetén (akárcsak a makróknál) nincs típusellenőrzés, csupán felhasználáskor kell, hogy a meghívott eljárás értelmezhető legyen. A pointerre az iterátor-eljárások (léptetés, értékadás, op*()) értelmezhetőek. Mire használjuk őket? lépni lehet a konténeren belül elemről elemre pontokat, intervallumokat lehet definiálni vele a konténeren belül Általánosan (mint már láthattuk): különböző tárolók interfészei algoritmusok számára pl. count() list-re, find() vectorra STL
Altípusai /Concepts/ (funkcionalitás szerint csoportosítva): "trivial" iterátor - az iterátort mint emelet elérő objektumot jellemzi Konstruktor X x; Érték elérése *x; Érték módosítása *x=y; (ha X módosítható - ez nincs mindig így) Tag elérése x->m (ezt nem támogatja mindegyik fordító) STL
Altípusai /Concepts/ (funkcionalitás szerint csoportosítva): előre haladó “forward iterator” (csak egy irányba léptethető) ++x; - referenciával tér vissza x++ - ekvivalens: {X tmp=i; ++i; return tmp;} kétirányú “bidirectional” (oda-vissza léphet) előre haladón túl: --x x-- STL
Altípusai /Concepts/ (funkcionalitás szerint csoportosítva): közvetlen elemelérésű “random” (tetszőleges lépésközzel haladhat) kétirányún túl: pointeraritmetika (+,-,+=,-=,<) közvetlen elemelérés: x[n]; közvetlen elemmódosítás: x[n]=y; STL
Altípusai /Concepts/ (funkcionalitás szerint csoportosítva): bemeneti “input” (az értéket csak kiolvasni lehet, írni nem!) triviálison (persze nem írható) és előre haladón túl: t=*x++; kimeneti “output” (csak írható) bizonyos szempontból a bemeneti ellentettje copy konstruktor érték megadása: *x=t; *x++=t; STL
Konstans (csak olvasható) iterátorok konténer<típus>::const_iterator név; konstans függvényekben használandó utal arra, hogy a konténert csak olvassuk példa: ostream &operator<<(ostream&, const konténer<T>&); STL
Mire jó az, hogy funkcionális csoportokat definiálunk? A könyvtári algoritmusok iterátorokkal érik el a konténereket viszont mindig csak bizonyos részeit használják az iterátorok funkcióinak (pl. összegzésnél: érték olvasása a=*x és előreléptetés ++x) Bevezethetünk saját konténert/iterátort, és hogy zökkenésmentes legyen ennek illesztése az algoritmusokhoz, ezek a funk. csoportok definiálják, milyen dolgokat kell az iterátorunknak teljesítenie. Ha saját algoritmust írunk, ami egy tárolót iterátorokon keresztül ér el, akkor ezekkel a tulajdonságokkal specifikálhatjuk, mit várunk el az iterátoroktól. STL
iterátorokkal kapcsolatos definíciók: "utolsó utáni első" "érvényes" vagy elérhető az iterátor alatt tárolt érték, vagy "utolsó utáni első" "növelhető" definiált a ++x - "utolsó utáni első"-kre ez nem igaz j "elérhető" i-ből, ha véges ++i alkalmazása után fennáll i == j [i,j) olyan "intervallum"-ot jelöl, mely i-től j-ig (j bele nem értendő) terjed [i,j) akkor "érvényes intervallum", ha i és j is érvényes, valamint i-ből "elérhető" j STL
Asszociatív tömb (map) Rendezett asszociatív tár, kulcs=>érték párokkal tulajdonságai: Az értékek nemcsak külső és belső find() függvénnyel, hanem operator[]-lel is elérhetőek (írásra és olvasásra) map1_demo.cc, map2_demo.cc Mivel rendezett tömbről van szó, a keresés/beszúrás/törlés O(log(n)) időben történik beszúrás történhet súgással (hint), így az O(log(n)) tovább rövidíthető STL
Asszociatív tömb (map) A konténerben párokban vannak az adatok tárolva pair<kulcs,érték>, iterátor alól ezeket Key k=(*iter).first és Value v=(*iter).second -del tudjuk kinyerni. iterátor alatt a kulcs nem módosítható: (*iter).first=new_k nem működik - hiszen akkor máshova kerülne az adat a rendezett tömbben. két azonos kulcsú adat nem szerepelhet a tárolóban (erre a multimap lett kitalálva) Pl.: map3_demo.cc STL
Házi feladat - Lázgörbe Statikus tömbök vektorrá alakítása + Vektorok elemeinek párosítása és map-be tétele + map kiírása az alábbi három tömbből készíts három vektort: int hour[]={6,8,14,23,18,16,21}; int min[]={11,22,33,44,55,31,41}; double dat[]={36.5,37.3,38.5,37.1,37.1,37.5,37.4}; definiáld a TimeStamp osztályt! Van benne kétparaméteres konstruktor (óra,perc) rendezési reláció (op<), ez const, és a paramétere is const &! friend kiírófv. (óra:perc) Töltsd fel a vektorokból a map<TimeStamp,double> konténert for ciklussal iteráljon végig egyszerre a vektorokon az órának és percnek megfelelő elemekből hozza létre a TimeStamp-et a map-be az adatokat op[] vagy insert() tagfv.-nyel is beteheted Írd ki a map tartalmát A megoldásban támaszkodj az előadás példaprogramjaira. STL
Halmaz (set) Elemek rendezett sora. Használjuk, ha: az elemek beviteli sorrendjének nincs szerepe ha direkt azt szeretnénk, hogy a beviteli sorrendtől ftl. saját sorrendünk legyen gyakorta kell halmazműveleteket végezni gyakorta kell keresni az elemek között az egyediség garantálásával nem akarunk külön foglalkozni (automatikusan elvégzi) Pl.: set1_demo.cc, set2_demo.cc STL
rendezési reláció asszociatív konténerekben tárolt elemeket sorba kell tudni rendezni beépített típusokra ez működik pointerekre is (ami nekünk fejfájást is okozott – emlékezz: funktorok demói) osztályokra??? definiálni kell a bool operator<(const T&, const T&) függvényt. Pl. less1_demo.cc STL
rendezési reláció Mi van akkor, ha ettől eltérő sorrendben szeretnénk az adatokat tárolni? A sablon szerint: set<Key, Compare, Alloc> - tehát Compare: összehasonlítás megadható Hogyan? Típusa: less<T>, ami egy funktor Ennek egyetlen tagfüggvénye: bool operator()(const T& x, const T& y) alapból az operator<-t hívja meg ezt kell felüldefiniálni. Pl. less2_demo.cc STL