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/06 19:53] – [Exception που συμβαίνουν στον κατασκευαστή της προγόνου κλάσης] 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 43: Line 45:
 </code> </code>
  
-Επιπλέον ο κατασκευαστή της κλάση Person παράγει ένα //exception// τύπου BadName. Η κλάσεις BadName και Περσον περιγράφονται παρακάτω:+Επιπλέον ο κατασκευαστή της κλάση Person παράγει ένα //exception// τύπου //BadName//. Η κλάσεις //BadName// και //Person// περιγράφονται παρακάτω:
  
 <code cpp BadName.hpp> <code cpp BadName.hpp>
Line 83: Line 85:
 Εάν μεταγλωττίσουμε και εκτελέσουμε την παρακάτω συνάρτηση //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 102: Line 109:
 </code> </code>
  
-Παρατηρήστε ότι καταστρέφεται το αντικείμενο //lastname//, αλλά όχι και το αντικείμενο //firstname//. Ο λόγος είναι ότι δημιουργηθεί ένα //exception// στον κατασκευαστή, δεν καλείται ποτέ ο καταστροφέας της κλάσης. Ως εκ τούτου, καταστρέφονται αυτόματα όλα τα αντικείμενα που έχουν δεσμευτεί στο //stack//, αλλά όχι τα αντικείμενα που είναι δεσμευσμένα στο //heap// (γενικότερα //resources// που περιμένουμε να απελευθερωθούν στον καταστροφέα).+Από τις εκτυπώσεις, παρατηρούμε ότι καταστρέφεται το αντικείμενο //lastname//, αλλά όχι και το αντικείμενο //firstname//. Ο λόγος είναι ότι δημιουργηθεί ένα //exception// στον κατασκευαστή, __δεν καλείται ποτέ ο καταστροφέας της κλάσης__Καταστρέφονται αυτόματα όλα τα αντικείμενα που έχουν δεσμευτεί στο //stack//, και λαμβάνει χώρα η διαδικασία του //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// και ένα στον κατασκευαστή της κλάσης στη γραμμή ''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 126: Line 135:
 </code> </code>
  
-Εάν ανανεώσετε τον κώδικα του κατασκευαστή τώρα το πρόγραμμα σας τυπώνει:+Εάν ανανεώσετε τον κώδικα του κατασκευαστή τώρα το πρόγραμμα σας κατά την εκτέλεση εκτυπώνει:
  
 <code> <code>
Line 141: Line 150:
  
 <WRAP tip 80% center round> <WRAP tip 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