Οι εξαιρέσεις στη γλώσσα C++ είναι μηχανισμοί που χρησιμοποιούνται για τη διαχείριση σφαλμάτων και αντιμετώπιση απροσδόκητων συμβάντων κατά την εκτέλεση ενός προγράμματος. Με τη χρήση εξαιρέσεων, μπορούμε να ανιχνεύουμε σφάλματα, να προκαλούμε σφάλματα και να αντιμετωπίζουμε αναπάντεχες καταστάσεις.
Ο τρόπος λειτουργίας των εξαιρέσεων είναι ο εξής: Όταν συμβαίνει μια ανεπιθύμητη κατάσταση ή ένα σφάλμα στο πρόγραμμα, εκτίθεται μια εξαίρεση, η οποία είναι ένα αντικείμενο που περιέχει πληροφορίες για το σφάλμα. Η εξαίρεση “ρίχνεται” (thrown) από το σημείο όπου συμβαίνει το σφάλμα και μπορεί να “πιαστεί” (caught) σε ένα σημείο ανωτέρου επιπέδου του προγράμματος που έχει τη δυνατότητα να τη διαχειριστεί.
Για να πετύχουμε αυτό τον μηχανισμό, χρησιμοποιούμε τις δηλώσεις try και catch. Στη δήλωση try τοποθετούμε τον κώδικα που μπορεί να ρίξει εξαίρεση, ενώ στη δήλωση catch τοποθετούμε τον κώδικα που θα εκτελεστεί για την περίπτωση που πιαστεί η εξαίρεση.
Με τη χρήση των εξαιρέσεων, μπορούμε να διαχειριστούμε σφάλματα, να ανακτήσουμε πληροφορίες για το σφάλμα και να προβούμε σε κατάλληλες ενέργειες για να αντιμετωπίσουμε το πρόβλημα, όπως αναστολή εκτέλεσης, εκτύπωση μηνυμάτων σφάλματος ή επανεκκίνηση του προγράμματος.
Οι λέξεις-κλειδιά try και catch στη C++ έρχονται σε ζευγάρια και χρησιμοποιούνται για τον χειρισμό των εξαιρέσεων στο πρόγραμμα.
Η δήλωση try καθορίζει ένα μπλοκ κώδικα που θα ελεγχθεί για τυχόν εξαιρέσεις κατά τη διάρκεια της εκτέλεσής του. Εάν προκύψει μια εξαίρεση μέσα στο μπλοκ try, η εκτέλεση του κώδικα στο try διακόπτεται και αναζητείται ένας αντίστοιχος χειριστής (catch handler).
Η λέξη-κλειδί throw χρησιμοποιείται για να “ρίξει” (throw) μια εξαίρεση μέσα από το μπλοκ try. Όταν συμβεί ένα πρόβλημα ή μια ανεπιθύμητη κατάσταση, μπορούμε να ρίξουμε μια εξαίρεση για να ειδοποιήσουμε το πρόγραμμα ότι κάτι πήγε στραβά.
Η δήλωση catch καθορίζει ένα μπλοκ κώδικα που θα εκτελεστεί μόνο εάν πιαστεί μια συγκεκριμένη εξαίρεση από το μπλοκ try. Οι δηλώσεις catch είναι υπεύθυνες για την επεξεργασία των εξαιρέσεων, παρέχοντας μια λύση για την αντιμετώπιση του προβλήματος ή την εκτέλεση κατάλληλων ενεργειών.
Με τη συνδυασμένη χρήση των try, throw και catch, μπορούμε να δημιουργήσουμε προσαρμοσμένα μηνύματα λάθους, να αντιμετωπίσουμε κρίσιμες καταστάσεις και να διαχειριστούμε τις εξαιρέσεις που προκύπτουν κατά την εκτέλεση του προγράμματος.
Παράδειγμα:
#include <iostream> int main() { try { int age = 15; // Ορίζουμε μια μεταβλητή age και την αρχικοποιούμε με την τιμή 15 if (age >= 18) { std::cout << "Είστε ενήλικας" << std::endl; // Εκτυπώνουμε ένα μήνυμα ότι είναι ενήλικας } else { throw(age); // Πετάει μια εξαίρεση, αν ο χρήστης είναι κάτω από 18 ετών } } catch (int myNum) { // Πιάνει την εξαίρεση που πετάχτηκε και τυπώνει ένα μήνυμα σφάλματος std::cout << "Έχετε μικρότερη ηλικία από την απαιτούμενη. Η ηλικία σας είναι: " << myNum << std::endl; } return 0; }
Ο παραπάνω κώδικας ελέγχει την ηλικία του χρήστη και εκτελεί δράσεις ανάλογα με την ηλικία που δόθηκε. Ας αναλύσουμε τη λειτουργία του:
- Ορίζεται η μεταβλητή
age
και της ανατίθεται η τιμή 15. - Έπειτα, γίνεται έλεγχος με την χρήση της συνθήκης
if
για να ελεγχθεί αν ηage
είναι μεγαλύτερη ή ίση με 18. - Αν η συνθήκη είναι αληθής, τότε εκτυπώνεται το μήνυμα “Είστε ενήλικας”.
- Αν η συνθήκη είναι ψευδής, τότε γίνεται η ρίψη μιας εξαίρεσης χρησιμοποιώντας την εντολή
throw(age)
. - Η εξαίρεση που πετάχτηκε πιάνεται από τον κλειδωμένο χειρισμό εξαιρέσεων
catch (int myNum)
. - Μέσα στο block
catch
, εκτυπώνεται ένα μήνυμα σφάλματος που περιέχει την ηλικία που περάστηκε στην εξαίρεση.
Έτσι, ο κώδικας ελέγχει αν ο χρήστης είναι ενήλικας ή όχι, και αν δεν είναι, τότε πετάει μια εξαίρεση που πιάνεται και εμφανίζει ένα μήνυμα σφάλματος με την ηλικία του χρήστη.
[adinserter block=”2″]
Ένα ακόμα παράδειγμα για το πώς μπορούμε να χρησιμοποιήσουμε το σύστημα εξαιρέσεων στη C++ είναι το παρακάτω:
#include <iostream> #include <stdexcept> double divide(double a, double b) { if (b == 0) { throw std::runtime_error("Δεν μπορείτε να διαιρέσετε με το μηδέν"); // Έλεγχος για διαίρεση με το μηδέν } return a / b; // Επιστρέφει το αποτέλεσμα της διαίρεσης } int main() { double x = 10.0; double y = 0.0; double z; try { z = divide(x, y); // Κλήση της συνάρτησης divide std::cout << "Το αποτέλεσμα της διαίρεσης είναι: " << z << std::endl; // Εκτύπωση του αποτελέσματος } catch (std::exception& e) { std::cout << "Σφάλμα: " << e.what() << std::endl; // Εκτύπωση σφάλματος αν προκύψει εξαίρεση } return 0; }
Ο παραπάνω κώδικας περιέχει τη δήλωση και τον ορισμό μιας συνάρτησης divide
, καθώς και την κλήση αυτής της συνάρτησης στην main
. Ας αναλύσουμε τον κώδικα γραμμή προς γραμμή:
- Εισαγωγή των απαραίτητων βιβλιοθηκών για την εκτέλεση του κώδικα.
- Ορισμός της συνάρτησης
divide
, η οποία δέχεται δύο παραμέτρους τύπουdouble
,a
καιb
. Αν τοb
είναι μηδέν, τότε εκτοξεύεται μια εξαίρεσηstd::runtime_error
, με ένα σχετικό μήνυμα. Διαφορετικά, επιστρέφεται το αποτέλεσμα της διαίρεσηςa / b
. - Η συνάρτηση
main
αρχίζει εδώ. Ορίζονται οι μεταβλητέςx
καιy
τύπουdouble
και αρχικοποιούνται με τιμές. - Δηλώνεται η μεταβλητή
z
τύπουdouble
. - Ένα μπλοκ
try
αρχίζει εδώ, σηματοδοτώντας την έναρξη της αναχώρησης εξαιρέσεων. - Καλείται η συνάρτηση
divide
με τις παραμέτρουςx
καιy
. Αν η διαίρεση είναι εφικτή, το αποτέλεσμα αποθηκεύεται στη μεταβλητήz
. - Αν δεν προκληθεί κάποια εξαίρεση κατά την εκτέλεση της συνάρτησης
divide
, εκτελείται αυτή η γραμμή που εμφανίζει το αποτέλεσμα της διαίρεσης στην οθόνη. - Αν προκληθεί κάποια εξαίρεση κατά την εκτέλεση της συνάρτησης
divide
, εκτελείται αυτή η γραμμή που εμφανίζει ένα μήνυμα σφάλματος στην οθόνη. - Η συνάρτηση
main
ολοκληρώνεται και επιστρέφει την τιμή 0, υποδεικνύοντας ότι το πρόγραμμα ολοκληρώθηκε επιτυχώς.
Ο κώδικας αυτός προσπαθεί να πραγματοποιήσει μια διαίρεση του αριθμού x
με τον αριθμό y
. Αν η διαίρεση είναι εφικτή, το αποτέλεσμα εκτυπώνεται στην οθόνη. Αν ο αριθμός y
είναι μηδέν, εκτοξεύεται μια εξαίρεση και εμφανίζεται ένα μήνυμα σφάλματος.
Αν δεν είστε εξοικειωμένοι με τον συγκεκριμένο τύπο εξαίρεσης που προκλήθηκε εντός του μπλοκ try, μπορείτε να χρησιμοποιήσετε τη σύνταξη “τρεις τελείες” (…) μέσα στο μπλοκ catch, το οποίο θα αντιμετωπίσει οποιοδήποτε τύπο εξαίρεσης.
Παράδειγμα:
#include <iostream> int main() { try { // Κάποιος κώδικας που μπορεί να προκαλέσει εξαίρεση } catch (...) { std::cout << "Προέκυψε ένα σφάλμα." << std::endl; } return 0; }
Σε αυτό το παράδειγμα, το μπλοκ try περιέχει κάποιον κώδικα που μπορεί να προκαλέσει εξαίρεση, αλλά δεν ξέρουμε ποιος είναι ο τύπος της εξαίρεσης. Στο μπλοκ catch χρησιμοποιούμε τις τρεις τελείες για να διαχειριστούμε οποιαδήποτε εξαίρεση προκύψει. Στη συνέχεια, εμφανίζουμε ένα απλό μήνυμα σφάλματος για να ενημερώσουμε τον χρήστη.
Η χρήση των τριών τελείων μπορεί να είναι χρήσιμη σε περιπτώσεις που δεν έχουμε πλήρη γνώση του κώδικα ή των συναρτήσεων που καλούνται στο μπλοκ try, και επιθυμούμε να διαχειριστούμε οποιοδήποτε είδος εξαίρεσης μπορεί να προκύψει. Ωστόσο, η χρήση των τριών τελείων μπορεί να καταστήσει τον κώδικα πιο δύσκολο στη συντήρηση, καθώς δεν έχουμε καμία εγγύηση για το ποιος τύπος εξαίρεσης μπορεί να προκύψει.
Επίσης, σημειώνουμε ότι, όπως και στην περίπτωση της δήλωσης catch με συγκεκριμένο τύπο εξαίρεσης, η δήλωση catch με τρεις τελείες πρέπει να τοποθετείται στο τέλος της αλυσίδας των δηλώσεων catch, ώστε να διασφαλίζεται ότι όλες οι εξαιρέσεις που δεν πιάνονται από τις προηγούμενες δηλώσεις catch θα πιαστούν από αυτή τη δήλωση.