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 [2018/05/20 14:26] – [Δήλωση των εξαιρέσεων που παράγουν οι συναρτήσεις (exception specifiers)] gthanoscpp:exception [2018/05/20 15:02] – [Κλείσιμο ανοιχτών resources όταν συμβεί ένα exception] gthanos
Line 416: Line 416:
 {{ :cpp:stack_unwinding.png |}} {{ :cpp:stack_unwinding.png |}}
  
-===== Κλείσιμο ανοιχτών resources όταν συμβεί ένα exception =====+===== Διαχείριση μίας εξαίρεσης και παραγωγή μίας νέας εξαίρεσης κατά την διαχείριση =====
  
-1. Διάβασμα από αρχείο και δέσμευση διδιάστατου πίνακα.+Κάποιες φορές είναι επιθυμητό να διαχειριστούμε μία εξαίρεση προκειμένου να κλείσουμε κάποιο //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 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 
 ===== Δήλωση των εξαιρέσεων που παράγουν οι συναρτήσεις (exception specifiers) ===== ===== Δήλωση των εξαιρέσεων που παράγουν οι συναρτήσεις (exception specifiers) =====
  
cpp/exception.txt · Last modified: 2023/05/15 14:01 by gthanos