cpp:exception
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
cpp:exception [2018/05/18 14:32] – [Κληρονομικότητα] gthanos | cpp:exception [2019/05/06 07:17] – [Κληρονομικότητα εξαιρέσεων] gthanos | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Διαχείριση Εξαιρέσεων ====== | + | ====== |
- | Ας εξετάσουμε την κλάση **Vector** που είδαμε στην υπερφόρτωση | + | Ας εξετάσουμε την κλάση **Vector** που είδαμε στην |
<code cpp Vector.cpp> | <code cpp Vector.cpp> | ||
Line 43: | Line 43: | ||
</ | </ | ||
- | Αν και η παραπάνω διαδικασία δεν είναι λανθασμένη, | + | Αν και η παραπάνω διαδικασία δεν είναι λανθασμένη, |
<code cpp VectorUse.cpp> | <code cpp VectorUse.cpp> | ||
Line 58: | Line 58: | ||
</ | </ | ||
- | Η παραγωγή ενός exception μπορεί να επιλύσει πιο αποτελεσματικά το παραπάνω πρόβλημα διότι | + | Η παραγωγή ενός |
<code cpp Vector.cpp> | <code cpp Vector.cpp> | ||
Line 78: | Line 78: | ||
Vector:: | Vector:: | ||
size = length; | size = length; | ||
- | array = new (nothrow) | + | array = new int[size]; |
for(int i=0; i<size; i++) | for(int i=0; i<size; i++) | ||
array[i] = 0; | array[i] = 0; | ||
Line 117: | Line 117: | ||
<WRAP tip 80% center round> | <WRAP tip 80% center round> | ||
- | Αν και στο παραπάνω απλό παράδειγμα είναι προφανές ότι είναι πιο απλό να ελέγξει κανείς το μέγεθος της παραμέτρου size πριν καλέσει τον κατασκευαστή, κάτι τέτοιο | + | Στο παραπάνω απλό παράδειγμα είναι προφανές ότι είναι πιο απλό να ελέγξει κανείς το μέγεθος της παραμέτρου |
</ | </ | ||
===== Τύποι παραγόμενων εξαιρέσεων ===== | ===== Τύποι παραγόμενων εξαιρέσεων ===== | ||
Line 133: | Line 133: | ||
===== Δημιουργία και διαχείριση της εξαίρεσης ===== | ===== Δημιουργία και διαχείριση της εξαίρεσης ===== | ||
- | Όπως σε όλες τις γλώσσες αντικειμενοστραφούς προγραμματισμού η παραγωγή μιας εξαίρεσης θα πρέπει να γίνει μέσα σε ένα //try block// και η διαχείριση της μέσα σε ένα //catch block// που ακολουθεί το //try block//. Δείτε το παρακάτω ενδεικτικό παράδειγμα. | + | Όπως σε όλες τις γλώσσες αντικειμενοστραφούς προγραμματισμού η παραγωγή μιας εξαίρεσης θα πρέπει να γίνει μέσα σε ένα //try block// και η διαχείριση της μέσα σε ένα //catch block// που ακολουθεί το //try block//. Δείτε το παρακάτω ενδεικτικό παράδειγμα, όπου ανάλογα με την είσοδο που βάζει ο χρήστης παράγεται διαφορετικού τύπου // |
<code cpp ExceptionHandling.cpp> | <code cpp ExceptionHandling.cpp> | ||
Line 164: | Line 164: | ||
break; | break; | ||
case 4: | case 4: | ||
- | throw string(" | + | throw string(" |
break; | break; | ||
case 5: | case 5: | ||
Line 170: | Line 170: | ||
break; | break; | ||
default: | default: | ||
- | c = -10; throw c; // throw a character | + | c = -10; throw c; // throw a character |
break; | break; | ||
} | } | ||
Line 183: | Line 183: | ||
} catch(const MyException &ex) { | } catch(const MyException &ex) { | ||
cout << "Got '"<< | cout << "Got '"<< | ||
- | } catch(...) { | + | } catch(...) { // catch any exception not caught above! |
cout << "Got an exception of unknown type!\n"; | cout << "Got an exception of unknown type!\n"; | ||
} | } | ||
Line 189: | Line 189: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | <WRAP info 80% center round> | ||
+ | Στον παραπάνω κώδικα το //catch block// | ||
+ | <code cpp> | ||
+ | } catch(...) { // catch any exception not caught above! | ||
+ | cout << "Got an exception of unknown type!\n"; | ||
+ | } | ||
+ | </ | ||
+ | πιάνει όλους τους τύπους // | ||
+ | </ | ||
<WRAP tip 80% center round> | <WRAP tip 80% center round> | ||
Line 194: | Line 204: | ||
</ | </ | ||
- | ===== Κληρονομικότητα ===== | ||
- | Ας υποθέσουμε ότι έχουμε τη σχέση κληρονομικότητας μεταξύ των κλάσεων **IDException** και **CountedIDException**, | + | ===== Stack Unwinding ===== |
- | <code cpp BaseException.h> | + | Κατά την δημιουργία ενός // |
- | using namespace std; | + | |
- | class BaseException: public | + | <code cpp StackUnwinding.cpp> |
- | protected: | + | #include < |
- | | + | // called by FFF() |
- | public: | + | void FFFF() { |
- | | + | std::cout << "Start FFFF\n"; |
- | | + | |
- | // | + | throw 100; |
- | | + | |
- | | + | |
- | return s; | + | } |
+ | // called by FF() | ||
+ | void FFF() { | ||
+ | std::cout << "Start FFF\n"; | ||
+ | | ||
+ | | ||
+ | } | ||
+ | // called by F() | ||
+ | void FF() { | ||
+ | | ||
+ | try { | ||
+ | | ||
+ | } catch(char) { | ||
+ | std::cerr << "FF caught double exception\n"; | ||
} | } | ||
- | }; | + | std::cout << "End FF\n"; |
- | </code> | + | } |
- | + | // called by main() | |
- | <code cpp DerivedException.h> | + | void F() { |
- | # | + | |
- | using namespace std; | + | |
- | + | FF(); | |
- | class DerivedException: | + | |
- | int b; | + | |
- | public: | + | |
- | | + | std::cerr << "F caught double exception\n"; |
- | | + | |
- | char *s = new char [64]; | + | |
- | sprintf(s, " | + | |
- | return s; | + | |
} | } | ||
- | }; | + | std:: |
- | </code> | + | } |
- | + | ||
- | <code cpp ExceptionUse.cpp> | + | |
- | #include < | + | |
- | # | + | |
- | using namespace std; | + | |
int main() { | int main() { | ||
+ | std::cout << "Start main\n"; | ||
try { | try { | ||
- | | + | |
- | cout << "Enter option | + | } catch (int) { |
- | cin >> option; | + | |
- | BaseException bex(-2); | + | |
- | DerivedException dex(4,5); | + | |
- | switch(option) { | + | |
- | case 1: | + | |
- | throw bex; | + | |
- | break; | + | |
- | case 2: | + | |
- | throw dex; | + | |
- | break; | + | |
- | } | + | |
- | } catch(BaseException ex) { | + | |
- | | + | |
- | } catch(DerivedException ex) { | + | |
- | cout << ex.what(); | + | |
} | } | ||
+ | std::cout << "End main\n"; | ||
return 0; | return 0; | ||
} | } | ||
</ | </ | ||
- | O παραπάνω κώδικας παράγει το παρακάτω //warning// κατά τη μεταγλώττιση: | + | Το αποτέλεσμα που εκτυπώνεται στην οθόνη |
< | < | ||
- | ExceptionUse.cpp: | + | Start main |
- | } catch(DerivedException &ex) { | + | Start F |
- | ^ | + | Start FF |
- | ExceptionUse.cpp: | + | Start FFF |
- | } catch(BaseException &ex) { | + | Start FFFF |
- | ^ | + | FFFF throwing int literal exception |
+ | F caught int exception | ||
+ | End F | ||
+ | End main | ||
</ | </ | ||
- | το οποίο | + | H εξέλιξη του //program stack// στο |
- | + | ||
- | Εκτελέστε όμως | + | |
- | < | + | |
- | gthanos@gthanos-DESKTOP: | + | |
- | Enter option (1-2): 1 | + | |
- | BaseException, | + | |
- | gthanos@gthanos-DESKTOP: | + | |
- | Enter option (1-2): 2 | + | |
- | BaseException, | + | |
- | </ | + | |
- | Παρατηρήστε ότι ενώ στην 2η περίπτωση παράγεται ένα // | + | {{ : |
- | Η απάντηση στο παραπάνω | + | ===== Διαχείριση μίας εξαίρεσης |
- | Ο τρόπος για να δουλέψει σωστά ο παραπάνω κώδικας είναι μέσα στο //catch block// να μην περάσουμε το αντικείμενο | + | Κάποιες φορές είναι επιθυμητό |
- | <code cpp ExceptionUse.cpp> | + | <code cpp PPMImageSample.cpp> |
#include < | #include < | ||
- | # | + | # |
+ | #include < | ||
+ | #include < | ||
using namespace std; | using namespace std; | ||
- | int main() { | + | class PPMImage { |
- | try { | + | |
- | | + | int **raster; |
- | | + | public: |
- | cin >> | + | PPMImage(char *filename) { |
- | | + | |
- | | + | |
- | | + | |
- | | + | if(!in.is_open()) { |
- | | + | std:: |
- | | + | throw fex; |
- | | + | |
- | | + | try { |
- | break; | + | in >> str; |
+ | in >> str; | ||
+ | width = atoi(str.c_str()); | ||
+ | in >> str; | ||
+ | height = atoi(str.c_str()); | ||
+ | in >> str; | ||
+ | colordepth = atoi(str.c_str()); | ||
+ | raster = new int*[height]; | ||
+ | for(int row=0; row< | ||
+ | raster[row] = new int[width]; | ||
+ | for(int row=0; row< | ||
+ | for(int col=0; col< | ||
+ | | ||
+ | red = (unsigned char) atoi(str.c_str()); | ||
+ | cin >> str; | ||
+ | green = (unsigned char) atoi(str.c_str()); | ||
+ | cin >> str; | ||
+ | blue = (unsigned char) atoi(str.c_str()); | ||
+ | raster[row][col] = 0; | ||
+ | raster[row][col] = (red << 16) | (green << 8) | blue; | ||
+ | } | ||
+ | } | ||
+ | | ||
+ | catch(std:: | ||
+ | cerr << " | ||
+ | in.close(); | ||
+ | throw ex; | ||
+ | | ||
+ | } | ||
+ | |||
+ | ~PPMImage() { | ||
+ | for(int row=0; row< | ||
+ | | ||
+ | delete raster; | ||
+ | } | ||
+ | |||
+ | int **getRaster() { return raster; } | ||
+ | |||
+ | }; | ||
+ | |||
+ | int main(int argc, char *argv[]) { | ||
+ | PPMImage *imgptr=nullptr; | ||
+ | try{ | ||
+ | imgptr = new PPMImage(argv[1]); | ||
+ | } | ||
+ | catch(ios_base::failure &fex) { | ||
+ | cerr << "File '" | ||
+ | } | ||
+ | catch(bad_alloc &ex) { | ||
+ | cerr << " | ||
+ | if (imgptr!=nullptr) { | ||
+ | cerr << " | ||
+ | if(imgptr-> | ||
+ | | ||
+ | | ||
+ | | ||
+ | else { | ||
+ | | ||
+ | } | ||
+ | delete imgptr; | ||
+ | } | ||
+ | else { | ||
+ | cerr << " | ||
} | } | ||
- | } catch(BaseException &ex) { | ||
- | cout << ex.what(); | ||
- | } catch(DerivedException &ex) { | ||
- | cout << ex.what(); | ||
} | } | ||
+ | delete imgptr; | ||
return 0; | return 0; | ||
} | } | ||
</ | </ | ||
- | Πλέον το αποτέλεσμα της εκτέλεσης είναι το αναμενόμενο | + | Το ενδεικτικό αρχείο εισόδου είναι το παρακάτω: |
+ | |||
+ | <code cpp 3x2.ppm> | ||
+ | P3 | ||
+ | 3 -2 255 | ||
+ | 255 0 0 255 255 0 0 255 255 | ||
+ | 255 0 255 0 255 0 128 128 128 | ||
+ | </ | ||
+ | |||
+ | Από τον παραπάνω κώδικα μπορούμε να συμπεράνουμε | ||
+ | - Εφόσον παράγεται ένα // | ||
+ | - Εάν εφαρμόσω τον τελεστή **delete** σε ένα δείκτη που έχει την τιμή **nullptr**, | ||
+ | |||
+ | ==== Ένα 2ο παράδειγμα ==== | ||
+ | |||
+ | Στο προηγούμενο παράδειγμα κάντε την εξής | ||
+ | |||
+ | <code cpp> | ||
+ | catch(std:: | ||
+ | cerr << " | ||
+ | in.close(); | ||
+ | throw ex; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Το //exception std:: | ||
< | < | ||
- | gthanos@gthanos-DESKTOP: | + | $> ./PPMImageSample 3x2.ppm |
- | Enter option (1-2): 1 | + | std::bad_alloc occured! |
- | BaseException, | + | terminate called after throwing an instance of 'std:: |
- | gthanos@gthanos-DESKTOP:~/ | + | what(): std::exception |
- | Enter option | + | Aborted (core dumped) |
- | DerivedException, | + | |
</ | </ | ||
- | ===== Stack Unwinding | + | Ο λόγος που συμβαίνει το παραπάνω είναι ότι το όταν το //catch block// παράγει και πάλι το // |
+ | |||
+ | <code cpp> | ||
+ | catch(std:: | ||
+ | cerr << " | ||
+ | in.close(); | ||
+ | throw; | ||
+ | } | ||
+ | </ | ||
+ | ===== Δήλωση των εξαιρέσεων που παράγουν οι συναρτήσεις (exception specifiers) | ||
+ | |||
+ | Κατά τη δήλωση μίας συνάρτησης είναι δυνατόν να ορίσετε εάν αυτή μπορεί να παράγει κάποιου είδους // | ||
+ | - '' | ||
+ | - '' | ||
+ | - '' | ||
+ | |||
+ | Τους παραπάνω ορισμούς είναι δυνατόν να τους συναντήσετε στις // | ||
+ | |||
+ | /* | ||
+ | ===== Function try blocks ===== | ||
+ | */ | ||
+ | |||
cpp/exception.txt · Last modified: 2023/05/15 14:01 by gthanos