User Tools

Site Tools


cpp:exception

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revisionBoth sides next revision
cpp:exception [2019/05/06 07:19] – [Stack Unwinding] gthanoscpp:exception [2019/05/06 07:21] gthanos
Line 119: Line 119:
 Στο παραπάνω απλό παράδειγμα είναι προφανές ότι είναι πιο απλό να ελέγξει κανείς το μέγεθος της παραμέτρου //size// πριν καλέσει τον κατασκευαστή. Σε αυτή την περίπτωση, ο έλεγχος θα πρέπει να γίνεται από το χρήστη της εκάστοτε βιβλιοθήκης, ενώ η βιβλιοθήκη δεν παρέχει καμία εγγύηση για τον τρόπο συμπεριφοράς της εάν περαστούν λανθασμένα ορίσματα. Τα //exceptions// εξασφαλίζουν ότι η βιβλιοθήκη θα παράξει μία εξαίρεση εάν η δέσμευση της μνήμης αποτύχει. Στο παραπάνω απλό παράδειγμα είναι προφανές ότι είναι πιο απλό να ελέγξει κανείς το μέγεθος της παραμέτρου //size// πριν καλέσει τον κατασκευαστή. Σε αυτή την περίπτωση, ο έλεγχος θα πρέπει να γίνεται από το χρήστη της εκάστοτε βιβλιοθήκης, ενώ η βιβλιοθήκη δεν παρέχει καμία εγγύηση για τον τρόπο συμπεριφοράς της εάν περαστούν λανθασμένα ορίσματα. Τα //exceptions// εξασφαλίζουν ότι η βιβλιοθήκη θα παράξει μία εξαίρεση εάν η δέσμευση της μνήμης αποτύχει.
 </WRAP> </WRAP>
 +
 ===== Τύποι παραγόμενων εξαιρέσεων ===== ===== Τύποι παραγόμενων εξαιρέσεων =====
  
Line 205: Line 206:
  
  
- 
-===== Διαχείριση μίας εξαίρεσης και παραγωγή νέας εξαίρεσης κατά την διαχείριση της ===== 
- 
-Κάποιες φορές είναι επιθυμητό να διαχειριστούμε μία εξαίρεση προκειμένου να κλείσουμε κάποιο //resource//, αλλά στη συνέχεια θέλουμε να παράγουμε ξανά την ίδια εξαίρεση προκειμένου η τελική διαχείριση να γίνει παρακάτω. Δείτε το επόμενο απόσπασμα κώδικα από την κλάση PPMImage. Εάν το αρχείο που διαβάζουμε περιέχει κατά λάθος μία αρνητική τιμή θα παραχθεί ένα //std::bad_alloc exception//. Δεν θέλουμε να το διαχειριστούμε μέσα στον κατασκευαστή, διότι σε αυτή την περίπτωση ο κατασκευαστής θα επιστρέψει κανονικά και ο χρήστης δεν θα έιναι σε θέση να γνωρίζει ότι συνέβη σφάλμα. Παρόλα αυτά, θα θέλαμε να διαχειριστούμε εν μέρη την εξαίρεση στον κατασκευαστή, ώστε να κλείσουμε το ανοιχτό //ifstream//, αλλά στη συνέχεια να παράγουμε την ίδια εξαίρεση την οποία θα κληθεί η διαχειριστεί η μέθοδος που δημιουργεί το αντικείμενο. 
- 
-<code cpp PPMImageSample.cpp> 
-#include <iostream> 
-#include <fstream> 
-#include <ios> 
-#include <cstdlib> 
- 
-using namespace std; 
- 
-class PPMImage { 
-  int width, height, colordepth; 
-  int **raster; 
-public: 
-  PPMImage(char *filename) { 
-    string str; 
-    unsigned char red, green, blue; 
-    ifstream in(filename); 
-    if(!in.is_open()) { 
-      std::ios_base::failure fex("File not found!"); 
-      throw fex; 
-    } 
-    try { 
-      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<height; row++) 
-        raster[row] = new int[width]; 
-      for(int row=0; row<height; row++) { 
-        for(int col=0; col<width; col++) { 
-          cin >> str; 
-          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::bad_alloc &ex) { 
-      cerr << "std::bad_alloc occured!\n"; 
-      in.close(); 
-      throw ex; 
-    } 
-  } 
-   
-  ~PPMImage() { 
-    for(int row=0; row<height; row++) 
-      delete raster[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 '" << argv[0] << "' was not found!\n"; 
-  } 
-  catch(bad_alloc &ex) { 
-    cerr << "Memory allocation failure!\n"; 
-    if (imgptr!=nullptr) { 
-      cerr << "imgptr != nullptr\n"; 
-      if(imgptr->getRaster() != nullptr) { 
-        cerr << "imgptr->getRaster() != nullptr\n"; 
-        delete imgptr->getRaster(); 
-      } 
-      else { 
-        cerr << "imgptr->getRaster() == nullptr\n"; 
-      } 
-      delete imgptr; 
-    } 
-    else { 
-      cerr << "imgptr == nullptr\n"; 
-    } 
-  } 
-  delete imgptr; 
-  return 0; 
-} 
-</code> 
- 
-Το ενδεικτικό αρχείο εισόδου είναι το παρακάτω: 
- 
-<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 
-</code> 
- 
-Από τον παραπάνω κώδικα μπορούμε να συμπεράνουμε τα εξής: 
-  - Εφόσον παράγεται ένα //exception// o δείκτης //imgptr// μέσα στο //catch block// της συνάρτησης //main// έχει την αρχική του τιμή, δηλαδή **nullptr**. Αυτό είναι λογικό με βάση τις αρχές του //stack unwinding// που συζητήσαμε προηγούμενα. 
-  - Εάν εφαρμόσω τον τελεστή **delete** σε ένα δείκτη που έχει την τιμή **nullptr**, δεν παράγεται κάποιου είδους //exception//, αλλά ο κώδικας συνεχίζει κανονικά. 
- 
-==== Ένα 2ο παράδειγμα ==== 
- 
-Στο προηγούμενο παράδειγμα κάντε την εξής αλλαγή. Αντικαταστήστε το //catch block// στον κατασκευαστή με το παρακάτω: 
- 
-<code cpp> 
-    catch(std::exception &ex) { 
-      cerr << "std::exception occured!\n"; 
-      in.close(); 
-      throw ex; 
-    } 
-</code> 
- 
-Το //exception std::bad_alloc// είναι απόγονος της κλάσης //std::exception// επομένως ο παραπάνω κώδικας θα πρέπει να δουλεύει σωστά και μετά την αλλαγή. Εν τούτοις παρατηρούμε ότι το πρόγραμμα αποτυγχάνει με ένα μήνυμα της μορφής 
-<code> 
-$> ./PPMImageSample 3x2.ppm  
-std::bad_alloc occured! 
-terminate called after throwing an instance of 'std::exception' 
-  what():  std::exception 
-Aborted (core dumped) 
-</code> 
- 
-Ο λόγος που συμβαίνει το παραπάνω είναι ότι το όταν το //catch block// παράγει και πάλι το //exception//, παράγει ένα αντικείμενο της κλάσης //std::exception// αποκόπτοντας το τμήμα του αντικειμένου που αφορά την απόγονο κλάση //std::bad_alloc//. Στη συνέχεια ένα τέτοιο αντικείμενο δεν μπορεί να το "πιάσει" το //catch block// της συνάρτησης //main//. Εάν πρέπει να παράγεται το ίδιο //exception// πράγμα που ήταν αρχικά επιθυμητό ο κώδικας στο //catch block// του κατασκευαστή θα πρέπει να γραφεί όπως παρακάτω, ώστε να παράγει ως //exception// το ίδιο αντικείμενο που έγινε //catch//. 
- 
-<code cpp> 
-    catch(std::exception &ex) { 
-      cerr << "std::exception occured!\n"; 
-      in.close(); 
-      throw;       // rethrows the same exception object 
-    } 
-</code> 
 ===== Δήλωση των εξαιρέσεων που παράγουν οι συναρτήσεις (exception specifiers) ===== ===== Δήλωση των εξαιρέσεων που παράγουν οι συναρτήσεις (exception specifiers) =====
  
cpp/exception.txt · Last modified: 2023/05/15 14:01 by gthanos