Hiba és kivételkezelés Hagyományos hibakezelési módszerek: • Befejezi a program futását • Hibakódot ad vissza • Hibakezelő fv. meghívása
Programozás alapjai II. (10. ea) C++ hibakezelés és STL bevezető Szeberényi Imre BME IIT
A C++ kivételkezeléssel a fentiek többékevésbé megoldhatók, sőt...
<
[email protected]>
MŰEGYTEM 1782 C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
-1C++ programozási nyelv
Kivételkezelés újból
© BME-IIT Sz.I.
2010.04.13.
Kivétel2
-3-
Kivétel1
Kritikus műveletek
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
-4-
Kivételkezelés példa
try { ..... Kritikus művelet1 if (hiba) throw kifejezés_tip1; ..... Kritikus művelet2 if (hiba) throw kifejezés_tip2; } catch (típus1 param) { ..... Kivételkezelés1 } catch (típus2 param) { ..... Kivételkezelés2 } ... további utasítások © BME-IIT Sz.I.
-2-
További műv.
Kivételkezelés/2
C++ programozási nyelv
2010.04.13.
Kivételkezelés = globális goto
• Hibák/kivételek kezelése gyakran nem a hiba keletkezésének helyén történik. • Legtöbbször a hiba keletkezésének helyén nem is tudjuk, hogy mit kell tenni, mert csak a programrészlet (függvény, könyvtár) felhasználója tudja ezt. • Első C++ órán láttuk, hogy a hibát felfedező kódrészlet típusorientált hibát dobhat, amit a hívó képes feldolgozni. C++ programozási nyelv
© BME-IIT Sz.I.
Hiba észlelése
double osztas(int y) { if (y == 0) throw "Osztas nullaval"; return((5.0/y); }
A típus azonosít
int main() Kritikus szakasz { try { cout << "5/2 =" << osztas(2) << '\n'; cout << "5/0 =" << osztas(0) << '\n'; } catch (const char *p) { cout << p << '\n'; Kivétel kez. } } 2010.04.13.
-5-
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
-6-
Újdonságok a korábbiakhoz
Következtetések • Célszerű kivétel osztályokat alkalmazni, (pl. std::exceptions) amiből származtatással újabb kivételeket lehet létrehozni. • A dobás értékparamétert dob, ezért az elkapáskor számolni kell az alaposztályra történő konverzióval (adatvesztés). Î Célszerű pointert, vagy referenciát alkalmazni. Î A dobott osztálynak kell. hogy legyen másoló konstruktora.
• A dobott kivétel alap ill. származtatott objektum is lehet. try { throw E(); } catch(H) { // mikor jut ide ? } 1. 2. 3. 4.
H és E azonos típusú, H bázisosztálya E-nek, H és E mutató és teljesül rájuk 1. vagy 2., H és E referencia és teljesül rájuk 1. vagy 2.
C++ programozási nyelv
© BME-IIT Sz.I.
-7-
2010.04.13.
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
Kivételek specifikálása
Továbbdobás
• Függvény deklarálásakor/definíciójakor megadható, hogy milyen kivételeket generál az adott függvény. • Ha mást is generálna, akkor az automatikusan meghívja az unexpected() handlert. void f1() throw (E1, E2); // csak E1, E2 void f2() throw(); // semmi void f3(); // bármi
try { throw E(); } catch(H) { if (le_tudjuk kezelni) { .... Az eredeti dobódik tovább, } else { nem csak az elkapott változat. throw; } } Paraméter nélkül
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
-9-
C++ programozási nyelv
Minden elkapása try { throw E(); } catch(...) { // szükséges feladatok throw; }
- 10 -
try { Minden a blokkban deklarált, "létező" A a; objektum destruktora meghívódik. B b; C *cp = new C; if (hiba) throw "Baj van"; delete cp; } catch(const char *p) { Hiba esetén C nem szabadul // A létezik ? fel, de cp megszűnik. // B létezik ? // *cp által mutatott obj. létezik ? }
Minden kivétel
© BME-IIT Sz.I.
2010.04.13.
Roll back
A kezelők sorrendje fontos!
C++ programozási nyelv
© BME-IIT Sz.I.
-8-
2010.04.13.
- 11 -
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 12 -
Melyik obj. létezik ?
Kivétel a konstruktorban • Lényegében a kivételkezelés az egyetlen mód arra, hogy a konstruktor hibát jelezzen. • Hiba esetén gondoskodni kell a megfelelő obj. állapot előállításáról. Inicializáló listán keletkező kivétel elfogása:
• Csak az az objektum számít létezőnek, amelynek a konstruktora lefutott. • Ha a konstruktor nem fut le, akkor a roll back során a destruktor sem fog végrehajtódni. • Előző példában C konstruktora lefutott ugyan, de nem deklarációval hoztuk létre, hanem dinamikusan. (Javaslat: std::auto_ptr) C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
class A { B b; public: A() try :b() { // konstruktor programozott része } catch (...) { // kivételkezelés } }; - 13 -
Kivétel a destruktorban
2010.04.13.
• Az ilyen esetekben külön figyelmet kell fordítani arra, hogy a feldolgozás közben észlelt hiba esetén is gondoskodjunk a felszabadításról. - 15 -
C++ programozási nyelv
2010.04.13.
// lezárás normál esetben
{
// file feldolgozása
} © BME-IIT Sz.I.
2010.04.13.
- 17 -
- 16 -
Erőforrás foglalás-felszabadítás/3
// lezárás hiba esetén // tovább
// megnyitás
try {
C++ programozási nyelv
© BME-IIT Sz.I.
class FILE_ptr { FILE *p; public: FILE_ptr(const char *n, const char *m) { p = fopen(n, m); } cast operator ~FILE_ptr { fclose(p); } operator FILE*() { return p; } };
FILE *fp = fopen("x.txt", "r");
- 14 -
– lefoglalás – feldolgozás – felszabadítás
Erőforrás foglalás-felszabadítás/2
} catch (...) { fclose(fp); throw; } fclose(fp);
2010.04.13.
• Gyakori, hogy erőforrásként kell kezelni valamit (memória, fájl, eszköz, stb.):
A::~A() try { // destruktor törzse } catch (...) { // kivételkezelés } © BME-IIT Sz.I.
© BME-IIT Sz.I.
Erőforrás foglalás-felszabadítás
Destruktor hívás oka: 1. Normál meghívás 2. Kivételkezelés (roll back) miatti meghívás. Ekkor a kivétel nem léphet ki a destruktorból. Destruktorban keletkező kivétel elfogása:
C++ programozási nyelv
C++ programozási nyelv
automatikus cast
FILE_ptr fp("x.txt", "r"); fprintf(fp, "Hello");
C++ programozási nyelv
destruktor megszüntet (bezár)
© BME-IIT Sz.I.
2010.04.13.
- 18 -
Szabványos könyvtár (STL)
Szabványos kivételek (stdexcept) bad_alloc bad_cast bad_typeid bad_exception ios_base::failure range_error overflow_error undeflow_error lenght_error domain_error out_of_range invalid_argument
Általános célú, újrafelhasználható elemek: – tárolók, majdnem tárolók – algoritmusok – függvények – bejárók – kivételek – memóriakezelők – adatfolyamok http://www.sgi.com/tech/stl/ http://www.cppreference.com/cppstl.html http://www.cplusplus.com/reference/stl/ C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 19 -
Szabványos kivételek/2
© BME-IIT Sz.I.
2010.04.13.
2010.04.13.
- 20 -
} catch (exception& e) { cout << "exeptionból származik" cout << e.what() << endl; } catch (...) { cout << "Ez valami más\n"; }
- 21 -
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 22 -
bad_exception példa void myhandler() { throw; // továbbdob -> bad_exception } void valami() throw (int, bad_exception) { throw 'c'; // karaktert dob, -> unexpected }
– bellálítja az unexpected handlert.
• unexpected() – meghívja az unexpected handlert. Ha ez nem várt kivételt dob, és a bad_exception lehetséges, akkor bad_exeption kivétel keletkezik. void f4() throw (E1, bad_exception);
int main (void) { set_unexpected(myhandler);// saját handlert állít try { valami(); } catch (exception &e) { cerr << e.what() << endl; } return 0; }
• set_terminate(void f()) – beállítja a terminate handlert
• terminate() – meghívja a terminate handlert 2010.04.13.
© BME-IIT Sz.I.
.....
• set_unexpected(voif f());
© BME-IIT Sz.I.
logic_error
• A standard könyvtár nem bővíti az exception osztály függvényeit, csak megfelelően átdefiniálja azokat. • A felhasználói programnak nem kötelessége az exceptionből származtatni, de célszerű. referencia try {
Kapcsolódó függvények
C++ programozási nyelv
runtime_error
Szabványos kivételek/3
class exeption { ... public: exception() throw(); exception(const exception&) throw(); execption& operator=(const exception&) throw(); virtual ~exception() throw(); virtual const char *what() const throw(); }; class runtime_error : public exception { public: explicit runtime_error(const string& what_arg); }; class logic_error : public exception { public: explicit logic_error(const string& what_arg ); };
C++ programozási nyelv
C++ programozási nyelv
exception
- 23 -
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 24 -
std::auto_ptr (memory)
std::auto_ptr /2
• Objektum sablon a <memory> -ban
{ auto_ptr
cp1, cp2(new C); cp2->valami(); Konstruktor inicializál cp1 = cp2; cp2 NULL lesz (*cp1).valami(); auto_ptr ip(new int); *ip.get() = 10; Új poi, előző felszabadul ip.reset(new int); int *ip2 = ip.release(); delete ip2; "Kézzel" szabadítunk fel } // cp1 és ip által mutatott obj. is megsemmisül
• Egy mutatót tárol. Megsemmisülésével a mutatott objektum is törlődik. • Műveletei: – kontruktor, destruktor – get(), reset(), release() – * ->, = – konvertáló operatorok C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 25 -
C++ programozási nyelv
Tárolók (konténerek) • • • • • •
vector i1(10, -3); vector<double> d1(100); i1[8] = 12; i1.at(9) = 13; for (vector<double>::size_type i = 0; i < d1.size(); i++) d1[i] = 3.14; for (vector::iterator i = i1.begin(); i < i1.end(); i++) cout << *i << endl; © BME-IIT Sz.I.
2010.04.13.
- 27 -
vector list deque stack queue priority_queue
C++ programozási nyelv
vector template
© BME-IIT Sz.I.
- 26 -
• • • •
map multimap set multiset
• • • •
string array valarray bitset
© BME-IIT Sz.I.
2010.04.13.
- 28 -
vector template/2
template > class vector { public: // Types typedef T value_type; typedef Allocator allocator_type; class iterator; class const_iterator; typedef typename Allocator::size_type size_type; typedef typename Allocator::difference_type difference_type; typedef typename Allocator::pointer pointer; typedef typename std::reverse_iterator reverse_iterator; ....
C++ programozási nyelv
2010.04.13.
Szabványos tárolók
• Tetszőleges adatok tárolására • Sorban, vagy tetszőleges sorrendben érhetők el az adatok. • Tipizált felületek
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 29 -
// Construct/Copy/Destroy explicit vector(const Allocator& = Allocator()); explicit vector(size_type, const Allocator& = Allocator ()); vector(size_type, const T&, const Allocator& = Allocator()); vector(const vector&); vector& operator=(const vector&); template void assign(InputIterator start, InputIterator finish); void assign(size_type, const); allocator_type get_allocator () const;
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 30 -
vector template/3
vector template/4
// Iterators iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; reverse_iterator rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const;
C++ programozási nyelv
© BME-IIT Sz.I.
// Capacity size_type size() const; size_type max_size() const; void resize(size_type); void resize(size_type, T); size_type capacity() const; bool empty() const; void reserve(size_type);
2010.04.13.
- 31 -
C++ programozási nyelv
vector template/5
© BME-IIT Sz.I.
vector iv(10, -1); cout << iv.front(); cout << iv.back(); int i = iv.[2];
2010.04.13.
- 33 -
Hozzáférés műveletei: • front() • back() • [] • at()
2010.04.13.
© BME-IIT Sz.I.
Verem és sorműveletek: • push_back() • pop_back() void ! • push_front() • pop_front()
iv.back() = 7; iv.front() = 12; iv[12] = 8; // nincs ellen. iv.at(12) = 8; // hibát dob
© BME-IIT Sz.I.
C++ programozási nyelv
2010.04.13.
- 34 -
Tárolókhoz tartozó műveletek/2
vector::reverse_iterator rit = iv.rbegin(); while (rit != iv.rend()) cout << *rit++; // ++ visszafelé!!! C++ programozási nyelv
- 32 -
// Modifiers void push_back(const T&); void pop_back(); iterator insert(iterator, const T&); void insert(iterator, size_type, const T&); template void insert(iterator, InputIterator, InputIterator); iterator erase(iterator); iterator erase(iterator, iterator); void swap(vector&); void clear() };
Tárolókhoz tartozó műveletek Bejárók műveletei: • begin() • end() • rbegin() • rend()
2010.04.13.
vector template/6
// Element Access reference operator[](size_type); const_reference operator[](size_type) const; reference at(size_type); const_reference at(size_type) const; reference front(); const_reference front() const; reference back(); const_reference back() const;
C++ programozási nyelv
© BME-IIT Sz.I.
- 35 -
iv.push_back(23); iv.push_back(88); int i = iv.back(); iv.pop_back(); iv.erase(iv.begin()); C++ programozási nyelv
Listaműveletek: • insert(p, x) • insert(p, n, x) • insert(p, first, last) • erase(p) • erase(first, last) • clear()
ez is iterator: int*
int v[] = {1, 2, 3}; iv.insert(iv.begin(), v, v+3); iterator © BME-IIT Sz.I.
2010.04.13.
- 36 -
Tárolókhoz tartozó műveletek/3 Egyéb műveletek: • size() • empty() • max_size() • swap() • get_allocator() • ==, != • <, <=, >, >=,
Tárolókhoz tartozó műveletek/4 Értékadások: • operator=(x) • assign(n,x) • assign(first, last)
Konstruktorok, destr.: • container() • conatiner(n) • container(n,x) • container(first, last) • container(x) • ~container()
vector iv, iv1; iv.assign(10, 0); iv1.assign(iv1.begin(), iv1.end());
int v[] = {1, 2, 3}; vector iv(v, v+3); vectorcv(10, '*'); vector iv2(iv); C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
map<double, int> big; big[2.3] = 8; big[3.4] = 13; map<double,int>::iterator bi = big.lower_bound(3); - 37 -
C++ programozási nyelv
© BME-IIT Sz.I.
vector Nincs: • push_front, pop_front • asszociatív op.
int v[] = {0, 1, 2}; vector iv(v, v+3); iv.push_back(3); iv.at(5) = 5; // hiba
iv.resize(7, -8); iv.at(5) = 5; // nincs hiba Print(iv) // 0,1,2,3,-8,5,-8,
Speciális műveletek: • merge(list), • merge(list, bpred) • remove(val) • remove_if(upred) • resize(n), resize(n, val) • sort(), sort(bpred) • splice(p, list) • splice(p, list, first) • splice(p, list, first, last) • unique(),unique(bpred)
template void Print(T& t) { for (T::iterator i = t.begin(); i != t.end(); i++) cout << *i << ", "; cout << endl; } © BME-IIT Sz.I.
2010.04.13.
- 39 -
C++ programozási nyelv
deque Nincs: • asszociatív op.
deque dq; dq.push_back(6); dq.push_front(9); Print(dq); // 9, 6, dq.resize(6, -3); Print(dq); //9, 6, -3, -3, -3,-3,
dq.back() = 1; Print(dq); // 9, 6, -3, -3, -3, 1, dq[2] = 2; Print(dq); // 9, 6, 2, -3, -3, 1, dq.at(3) = 0;
Nincs: • at(), operator[]() • asszociatív op. list il(2, -3); il.push_front(9); il.push_back(2); il.sort(); Print(il); // -3, -3, 2, 9, il.unique(); list il2(3, 4); il.merge(il2); Print(il); // -3, 2, 4, 4, 4, 9,
© BME-IIT Sz.I.
2010.04.13.
- 40 -
Elrejti a kétvégű sor nem verem stílusú műveleteit. Műveletek: • empty() • push() • pop() • top() • stack() • stack(cont)
stack s; s.push(1); s.push(2); s.push(3); s.top() = 4; s.push(13);
while (!s.empty()) { cout << s.top() << ", "; s.pop(); } // 13, 4, 2, 1,
if (!dq.empty()) Print(dq); // 9, 6, 2, 0, -3, 1, © BME-IIT Sz.I.
- 38 -
stack
Kétvégű sor Speciális műveletek: • resize(n), resize(n, val)
C++ programozási nyelv
2010.04.13.
list
Speciális műveletek: • capacity() • reserve() • resize(n), resize(n, val)
C++ programozási nyelv
Asszociatív műveletek: • operator[](k) • find(k) • lower_bound(k) • upper_bound(k) • equal_range(k) • key_comp() • value_comp() • count()
2010.04.13.
- 41 -
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 42 -
queue
priority_queue
Elrejti a kétvégű sor nem sor stílusú műveleteit.
Prioritásos sor. Alapesetben a < operátorral hasonlít.
Műveletek: • empty() • push() –> push_back() • pop() –> pop_front() • front() • back() • queue(), queue(cont)
Műveletek: • empty() • push() • pop() • top() • priority_queue()
queue q; q.push(1); q.push(2); q.push(3); q.back() = 4; q.push(13);
while (!q.empty()) { cout << q.front() << ", "; q.pop(); } // 1, 2, 4, 13, C++ programozási nyelv
© BME-IIT Sz.I.
priority_queue pq; pq.push(1); pq.push(2); pq.push(3); pq.push(-2); pq.push(13);
while (!pq.empty()) { cout << pq.top() << ", "; pq.pop(); } // 13, 3, 2, 1, -2, 2010.04.13.
- 43 -
map
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
pair
Asszociatív tömb – (kulcs, érték) pár tárolása – alapértelmezés szerint < operátorral hasonlít – map maga is összehasonlítható
Párok – map bejárásakor párok sorozatát kapjuk – A kulcsra first, az értékre second mezővel hivatkozhatunk
map<string, int> m; m["haho"] = 8; m["Almas"] = 23; cout << m["haho"] << endl; cout << m["Almas"] << endl; map<string, int>::iterator i = m.find("haho");
map<string, int> m; m["haho"] = 8; m["Almas"] = 23; m["xx"] = 13; map<string, int>::iterator p; for (p = m.begin(); p != m.end(); p++) { cout << p->first << ": "; cout << p->second << ", "; } // almas: 23, haho: 8, xx: 13
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 45 -
set Halmaz – olyan map, ahol nem tároljuk az értéket – alapértelmezés szerint < operátorral hasonlít – map-hoz hasonlóan összehasonlítható set s; s.insert(3); s.insert(3); s.insert(7); s.insert(12); s.insert(8); cout << s.count(6) << endl; // 0 cout << s.count(3) << endl; // 1 set::iterator i = s.find(3); Print(s); // 3, 7, 8, 12, C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 44 -
- 47 -
C++ programozási nyelv
© BME-IIT Sz.I.
2010.04.13.
- 46 -