User Tools

Site Tools


cpp:function_try_blocks

Differences

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

Link to this comparison view

Next revision
Previous revision
Next revisionBoth sides next revision
cpp:function_try_blocks [2019/05/06 15:12] – created gthanoscpp:function_try_blocks [2019/05/15 08:24] – [Function Try Blocks] gthanos
Line 1: Line 1:
-====== Εξαιρέσεις στον κατασκευαστή ======+====== Εξαιρέσεις που παράγονται στον κατασκευαστή ======
  
 Ας υποθέσουμε ότι έχουμε την παρακάτω κλάση //Name// η οποία περιγράφει ένα όνομα Ας υποθέσουμε ότι έχουμε την παρακάτω κλάση //Name// η οποία περιγράφει ένα όνομα
  
 <code cpp Name.hpp> <code cpp Name.hpp>
 +#include <cstring>
 +
 class Name { class Name {
   char* name;   char* name;
Line 39: Line 41:
 και την κλάση //Person// η οποία περιγράφει έναν άνθρωπο. Η κλάση διαθέτει τα εξής δύο πεδία: και την κλάση //Person// η οποία περιγράφει έναν άνθρωπο. Η κλάση διαθέτει τα εξής δύο πεδία:
 <code cpp>  <code cpp> 
-  Name* firstname;  // pointer  +  Name* firstname;  // pointer to Name 
-  Name lastname;+  Name lastname;    // Name
 </code> </code>
  
-Επιπλέον ο κατασκευαστή της κλάση Person παράγει ένα //exception// τύπου BadName. Η κλάσεις BadName και Περσον περιγράφονται παρακάτω: +Επιπλέον ο κατασκευαστή της κλάση Person παράγει ένα //exception// τύπου //BadName//. Η κλάσεις //Person// και //BadName// περιγράφονται παρακάτω:
- +
-<code cpp BadName.hpp> +
-class BadName : public std::exception { +
-public: +
-  const char* what() { +
-    return "BadName"; +
-  } +
-}; +
-</code>+
  
 <code cpp Person.hpp> <code cpp Person.hpp>
Line 79: Line 72:
   delete firstname;   delete firstname;
 } }
 +</code>
 +
 +<code cpp BadName.hpp>
 +class BadName : public std::exception {
 +public:
 +  const char* what() {
 +    return "BadName";
 +  }
 +};
 </code> </code>
  
 Εάν μεταγλωττίσουμε και εκτελέσουμε την παρακάτω συνάρτηση //main// ο κώδικας εκτυπώνει τα εξής: Εάν μεταγλωττίσουμε και εκτελέσουμε την παρακάτω συνάρτηση //main// ο κώδικας εκτυπώνει τα εξής:
 <code cpp main.cpp> <code cpp main.cpp>
 +#include <iostream>
 +using namespace std;
 +
 +#include "Person.hpp"
 +
 int main() { int main() {
   try {   try {
Line 99: Line 106:
 Name destructor: Snow Name destructor: Snow
 Name destructor: Snow Name destructor: Snow
-Occured: BadName+Exception occured: BadName
 </code> </code>
  
-Παρατηρήστε ότι καταστρέφεται το αντικείμενο //lastname//, αλλά όχι και το αντικείμενο //firstname//. Ο λόγος είναι ότι δημιουργηθεί ένα //exception// στον κατασκευαστή, δεν καλείται ποτέ ο καταστροφέας της κλάσης. Ως εκ τούτου, καταστρέφονται αυτόματα όλα τα αντικείμενα που έχουν δεσμευτεί στο //stack//, αλλά όχι τα αντικείμενα που είναι δεσμευσμένα στο //heap// (γενικότερα //resources// που περιμένουμε να απελευθερωθούν στον καταστροφέα).+Από τις εκτυπώσεις, παρατηρούμε ότι καταστρέφεται το αντικείμενο //lastname//, αλλά όχι και το αντικείμενο //firstname//. Ο λόγος είναι ότι δημιουργηθεί ένα //exception// στον κατασκευαστή, __δεν καλείται ποτέ ο καταστροφέας της κλάσης__Καταστρέφονται αυτόματα όλα τα αντικείμενα που έχουν δεσμευτεί στο //stack//, και λαμβάνει χώρα η διαδικασία του //[[cpp:stack_unwinding|stack unwinding]]//
 + 
 +Ως εκ τούτου, δεν καταστρέφονται τα αντικείμενα που είναι δεσμευμένα στο //heap// και γενικότερα τα //resources// που περιμένουμε να απελευθερωθούν στον καταστροφέα της κλάσης.
  
 <WRAP tip 80% center round> <WRAP tip 80% center round>
-Ο λόγος που εκτυπώνεται 2 φορές το μήνυμα **"Name destructor: Snow"**, είναι διότι δημιουργούνται δύο αντικείμενα τύπου Name, ένα κατά την αρχικοποίηση του αντικειμένου //Person// και ένα στον κατασκευστή της κλάσης στη γραμμή ''lastname = Name(last);''+Ο λόγος που εκτυπώνεται 2 φορές το μήνυμα **"Name destructor: Snow"**, είναι διότι δημιουργούνται δύο αντικείμενα τύπου Name, ένα κατά την αρχικοποίηση του αντικειμένου //Person// (με τη βοήθεια του //default constructor//)και ένα στον κατασκευαστή της κλάσης στη γραμμή ''lastname = Name(last);''
 </WRAP> </WRAP>
  
 ===== Function Try Blocks ===== ===== Function Try Blocks =====
  
-Προκειμένου να λυθεί το συγκεκριμένο πρόβλημα η //C++// υποστηρίζει τα λεγόμενα //function try blocks//. Ουσιάστικά πρόκειται για μία ειδική σύνταξη //try - catch// που περιλαμβάνει το σύνολο του κατασκευαστή, ως εξής:+Προκειμένου να λυθεί το συγκεκριμένο πρόβλημα η //C++// υποστηρίζει τα λεγόμενα //function try blocks//. Ουσιαστικά πρόκειται για μία ειδική σύνταξη //try - catch// που περιλαμβάνει το σύνολο του κατασκευαστή, ως εξής:
  
 <code cpp > <code cpp >
Line 121: Line 130:
 } }
 catch(BadName& ex) { catch(BadName& ex) {
-  cout << "--> firstname deleted!" << endl;+  cout << "\n--> firstname deleted!" << endl;
   delete firstname;   delete firstname;
 } }
 </code> </code>
  
-Εάν ανανεώσετε τον κώδικα του κατασκευαστή τώρα το πρόγραμμα σας τυπώνει:+Εάν ανανεώσετε τον κώδικα του κατασκευαστή τώρα το πρόγραμμα σας κατά την εκτέλεση εκτυπώνει:
  
 <code> <code>
Line 135: Line 144:
 Name destructor: Snow Name destructor: Snow
 Name destructor: Snow Name destructor: Snow
 +
 --> firstname deleted! --> firstname deleted!
 Name destructor: John Name destructor: John
-Occured: BadName+Exception occured: BadName
 </code> </code>
  
-<WRAP tip 80% center round> +<WRAP important 80% center round> 
-Παρατηρήστε ότι αν και εκτελείται ο κώδικας μέσα στο //catch block//, η εξαίρεση "μεταφέρεται" και στη συνάρτηση //main///. Ο λόγος είναι ότι υποχρεωτικά η εξαίρεση, παράγεται ξανά στο τέλος του //catch block//. Ο μόνος τρόπος να το αποφύγετε αυτό είναι να κάνετε //throw// μία εξαίρεση διαφορετικού τύπου. +Παρατηρήστε ότι αν και εκτελείται ο κώδικας μέσα στο //catch block//, η εξαίρεση "μεταφέρεται" και στη συνάρτηση //main//. Ο λόγος είναι ότι η εξαίρεση, **αναπαράγεται αυτόματα** στο τέλος του //catch block//. Ο μόνος τρόπος να το αποφύγετε αυτό είναι να κάνετε //throw// μία νέα εξαίρεσηδιαφορετικού τύπου. 
-</code>+</WRAP>
  
-===== Exception που συμβαίνουν στον κατασκευαστή προγόνου κλάσης =====+===== Exception που συμβαίνουν στον κατασκευαστή της προγόνου κλάσης =====
  
-Ας υποθέσουμε την κλάση //Student// που είναι απόγοντος της κλάσης //Person// και δηλώνεται ως εξής:+Ας υποθέσουμε την κλάση //Student// που είναι απόγονος της κλάσης //Person// και δηλώνεται ως εξής:
  
 <code cpp Student.hpp> <code cpp Student.hpp>
-Student::Student(const char *first, const char *last, int id) try: Person(first, last), aem(id) {+class Student: public Person { 
 +  int aem; 
 +public: 
 +  Student(const char *first, const char *last, int id); 
 +}; 
 + 
 +Student::Student(const char *first, const char *last, int id): Person(first, last), aem(id) {
   cout << "Student constructor" << endl;   cout << "Student constructor" << endl;
 +
 +</code>
 +
 +Εάν επιθυμούμε να "πιάσουμε" την εξαίρεση εντός του κατασκευαστή της κλάσης //Student// θα πρέπει να κρατήσουμε τον κατασκευαστή της κλάσης //Person// στην αρχική του μορφή και να ξαναγράψουμε τον κατασκευαστή:
 +
 +<code cpp Student.hpp>
 +class Student: public Person {
 +  int aem;
 +public:
 +  Student(const char *first, const char *last, int id);
 +};
 +
 +Student::Student(const char *first, const char *last, int id) try : Person(first, last), aem(id) {
 +  cout << "Student constructor" << endl;
 +
 +catch(BadName& ex) {
 +  cout << "--> firstname deleted!" << endl;
 +  delete firstname;
 +}
 +</code>
 +
 +Η παραπάνω σύνταξη επιτρέπει να πιάσουμε το exception που συμβαίνει στον κατασκευαστή της προγόνου κλάσης. Και εδώ το //exception// θα αναπαραχθεί σύμφωνα με τους κανόνες που ίσχυσαν και στο προηγούμενο παράδειγμα. Παρατηρήστε ότι δεν εκτυπώνεται ποτέ το μήνυμα **"Student constructor"** του κατασκευαστή. Γιατί?
 +
 +Η μέθοδος //main// δίνεται παρακάτω:
 +
 +<code cpp main.cpp>
 +#include <iostream>
 +using namespace std;
 +
 +#include "Person.hpp"
 +#include "Student.hpp"
 +
 +int main() {
 +  try {
 +    Student johnSnow("John", "Snow", 1234);
 +  } catch(BadName& a) {
 +    cout << "Exception occured: " << a.what() << endl;
 +  }
 } }
 </code> </code>
  
cpp/function_try_blocks.txt · Last modified: 2022/05/23 06:05 by gthanos