1 // 2 // Hogyan kezeljük le a kivételes eseményeket? 3 // 4 5 // 6 // C-stílus 7 // 8 9 struct record { ... }; 10 11 record r; 12 extern int errno; 13 14 FILE *fp; 15 16 if ( (fp = fopen( "fname", "r")) != NULL ) 17 { 18 fprintf( stderr, "can't open file %s\n", "fname"); 19 errno = 1; 20 } 21 else if ( ! fseek( fp, 0L, n*sizeof(r)) ) 22 { 23 fprintf( stderr, "can't find record %d\n", n); 24 errno = 2; 25 } 26 else if ( 1 != fread( &r, sizeof(r), 1, fp) ) 27 { 28 fprintf( stderr, "can't read record\n"); 29 errno = 3; 30 } 31 else ... 32 33 34 // 35 // assert 36 // 37 38 #include <cassert> 39 40 int main() 41 { 42 ... 43 assert( ptr != 0 ); 44 ... 45 } 46 47 48 // 49 // setjmp/longjmp a C nyelvben 50 // 51 52 #include <setjmp.h> 53 #include <stdio.h> 54 55 jmp_buf x; // globális változó, vagy paraméterként át kell adni 56 57 // ez a függvény fog kivételt kiváltani 58 void f() 59 { 60 if ( ...hibát észlelünk... ) 61 longjmp(x,5); // kiváltja a kivételt 62 } 63 64 int main() 65 { 66 int i = 0; 67 68 // setjmp elsőre 0-val tér vissza 69 // másodszorra a longjmp() paraméterével 70 if ( (i = setjmp(x)) == 0 ) 71 { 72 // első alkalommal ide jutunk 73 f(); 74 } 75 else 76 { 77 // a kivétel esetén jutunk ide 78 switch( i ) 79 { 80 case 1: /* lekezeljük a hibát */ 81 case 2: /* lekezeljük a másik hibát */ 82 default: fprintf( stdout, "error code = %d\n", i); break; 83 } 84 } 85 return 0; 86 } 87 88 89 A kivételkezelés célja 90 91 - vezérlésátadás a hiba detektálásának helyéről (a cél ismeretlen) 92 - tetszőleges adat továbbítása típusbiztosan a handlerhez 93 - minden kivételt a megfelelő handler kapjon el 94 - a kivételek legyenek csoportosíthatóak 95 - működjön helyesen többszálas, párhuzamos környezetben 96 97 - ha nem váltunk ki kivételt, akkor ne legyen kód/futásiidő költség 98 - működjön együtt más nyelvekkel, és az operációs rendszerrel 99 100 101 102 A kivételkezelés összetevői: 103 104 - try block 105 - catch handlers 106 - throw expression 107 108 109 try 110 { 111 // ez a felügyelt kódrészlet 112 f(); 113 } 114 catch (T1 e1) { /* handler T1 típusra */ } 115 catch (T2 e2) { /* handler T2 típusra */ } 116 catch (T3 e3) { /* handler T3 típusra */ } 117 // ha nem volt kivétel, itt folytatódik 118 119 120 void f() 121 { 122 //... 123 T e; 124 throw e; /* T típusú e objektumot dob */ 125 126 // vagy: 127 throw T(); /* a T típusú default értéket dobja */ 128 } 129 130 131 Egy H típusú handler akkor kapja el az E típusú kivételt, ha: 132 133 - H és E megegyező típusok 134 - H egyértelmű bázisosztálya E-nek 135 - H és E pointerek vagy referenciák és fennáll 1 vagy 2 136 137 138