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 revision
Previous revision
Next revisionBoth sides next revision
cpp:exception [2018/05/18 14:32] – [Κληρονομικότητα] gthanoscpp:exception [2018/05/19 06:43] – [Stack Unwinding] gthanos
Line 282: Line 282:
 </code> </code>
  
-Παρατηρήστε ότι ενώ στην 2η περίπτωση παράγεται ένα //DerivedException// το αντικείμενο που τελικά λαμβάνουμε είναι τύπου //BaseException//. Εδώ θα πρέπει να τονίσουμε ότι η συνάρτηση //what()// είναι //virtual// πράγμα που σημαίνει ότι θα πρέπει να καλείται η κατάλληλη συνάρτηση με βάση τον τύπο του αντικειμένου, ανεξάρτητα από τον τύπο της μεταβλητής.+Παρατηρήστε ότι ενώ στην 2η περίπτωση παράγεται ένα //DerivedException// το αντικείμενο που τελικά λαμβάνουμε είναι τύπου //BaseException//. Εδώ θα πρέπει να τονίσουμε ότι η συνάρτηση //what()// είναι //virtual// πράγμα που σημαίνει ότι θα πρέπει να καλείται η κατάλληλη έκδοση της συνάρτησης με βάση τον τύπο του αντικειμένου για το οποίο καλείται, ανεξάρτητα από τον τύπο της η οποία δείχνει στο αντικείμενο (δες [[cpp:polymorphism|δυναμικό πολυμορφισμό]]).
  
-Η απάντηση στο παραπάνω ερώτημα είναι ότι αν και παράγεται ένα αντικείμενο τύπου //DerivedException// αυτό γίνεται //catch// από το πρώτο //catch block//. Μέσα στο //catch block// το αρχικό αντικείμενο αντιγράφεται καθώς έχουμε κλήση με τιμή σε ένα άλλο αντικείμενο τύπου //BaseException//. Πρακτικά αυτό σημαίνει ότι από το αρχικό αντικείμενο κρατάμε οτιδήποτε ανήκει στην κλάση //BaseException// και απορρίπτουμε το υπόλοιπο.+Η απάντηση στο παραπάνω ερώτημα είναι ότι αν και παράγεται ένα αντικείμενο τύπου //DerivedException// αυτό γίνεται //catch// από το πρώτο //catch block//. Μέσα στο //catch block// το αρχικό αντικείμενο αντιγράφεται σε ένα άλλο αντικείμενο τύπου //BaseException//, διότι έχουμε κλήση με τιμή στο //catch block//. Πρακτικά αυτό σημαίνει ότι από το αρχικό αντικείμενο κρατάμε οτιδήποτε ανήκει στην κλάση //BaseException// και απορρίπτουμε το υπόλοιπο.
  
 Ο τρόπος για να δουλέψει σωστά ο παραπάνω κώδικας είναι μέσα στο //catch block// να μην περάσουμε το αντικείμενο γιατί δημιουργείται αντίγραφο, αλλά να περάσουμε μία αναφορά σε αυτό, όπως παρακάτω: Ο τρόπος για να δουλέψει σωστά ο παραπάνω κώδικας είναι μέσα στο //catch block// να μην περάσουμε το αντικείμενο γιατί δημιουργείται αντίγραφο, αλλά να περάσουμε μία αναφορά σε αυτό, όπως παρακάτω:
Line 326: Line 326:
 DerivedException, a: 4, b: 5 DerivedException, a: 4, b: 5
 </code> </code>
 +
 +<WRAP tip 80% center round>
 +Το πιάσιμο μιας εξαίρεσης με χρήση αναφοράς για αντικείμενα σύνθετους τύπου (όχ char, int, long, double κλπ), διότι //α)// αποφεύγουμε την αντιγραφή του αντικειμένου μέσα στο //catch block// (πιο γρήγορος κώδικας) και //β)// αποφεύγουμε την "αποκοπή" μέρους του αντικειμένου που γίνεται //throw// λόγω του "πιασίματος" της εξαίρεσης από ένα //catch block// βασικότερου τύπου από τον τύπο που γίνεται //throw//.
 +</WRAP>
  
 ===== Stack Unwinding ===== ===== Stack Unwinding =====
  
 +Κατά την δημιουργία ενός //exception// μέσα σε μία συνάρτηση ή σε ένα κατασκευαστή δεν είναι απαραίτητο ότι η διαχείριση του //exception// θα πρέπει να γίνει στην ίδια τη συνάρτηση ή τον καστασκευαστή. Η διαδικασία όνομάζεται //stack unwinding// και το παράδειγμα που ακολουθεί είναι εξαρειτικά διαφωτιστικό για το πως διαμορφώνεται το stack μετά από την διαχείριση μίας εξαίρεσης σε υψηλότερο επίπεδο.
 +
 +<code cpp StackUnwinding.cpp>
 +#include <iostream>
 +// called by FFF()
 +void FFFF() {
 +  std::cout << "Start FFFF\n";
 +  std::cout << "FFFF throwing int literal exception\n";
 +  throw 100;
 +  std::cout << "End FFFF\n";
 + 
 +}
 +// called by FF() 
 +void FFF() {
 +  std::cout << "Start FFF\n";
 +  FFFF();
 +  std::cout << "End FFF\n";
 +}
 +// called by F()
 +void FF() {
 +  std::cout << "Start FF\n";
 +  try {
 +    FFF();
 +  } catch(char) { 
 +    std::cerr << "FF caught double exception\n";
 +  }
 +  std::cout << "End FF\n";
 +}
 +// called by main()
 +void F() {
 +  std::cout << "Start F\n";
 +  try {
 +    FF();
 +  } catch (int) {
 +     std::cerr << "F caught int exception\n";
 +  } catch (char) {
 +     std::cerr << "F caught double exception\n";
 +  }
 +  std::cout << "End F\n";
 +}
 + 
 +int main() {
 +  std::cout << "Start main\n";
 +  try {
 +    F();
 +  } catch (int) {
 +    std::cerr << "main caught int exception\n";
 +  }
 +  std::cout << "End main\n"; 
 +  return 0;
 +}
 +</code>
 +
 +Το αποτέλεσμα που εκτυπώνεται στην οθόνη είναι το εξής:
 +<code>
 +Start main
 +Start F
 +Start FF
 +Start FFF
 +Start FFFF
 +FFFF throwing int literal exception
 +F caught int exception
 +End F
 +End main
 +</code>
 +
 +H εξέλιξη του //program stack// στο παρακάτω πρόγραμμα δίνεται στο παρακάτω διάγραμμα. Παρατηρήστε ότι το exception παράγεται στη συνάρτηση **FFFF()**, αλλά "πιάνεται" στην **F()** πράγμα που συνεπάγεται την αυτόματη συρρίκνωση του //stack// στο επίπεδο της συνάρτησης **F()**. Μετά το "πιάσιμο" του //exception//, τα περιεχόμενα του //stack// για τις συναρτήσεις **FFF()** και **FFFF()** έχουν χαθεί.
  
 +{{ :cpp:stack_unwinding.png |}}
  
  
  
  
cpp/exception.txt · Last modified: 2023/05/15 14:01 by gthanos