User Tools

Site Tools


cpp:stack_unwinding

Stack Unwinding

Κατά την δημιουργία ενός exception μέσα σε μία συνάρτηση ή σε ένα κατασκευαστή δεν είναι απαραίτητο ότι η διαχείριση του exception θα πρέπει να γίνει στην ίδια τη συνάρτηση ή τον καστασκευαστή. Η διαδικασία όνομάζεται stack unwinding και το παράδειγμα που ακολουθεί είναι εξαρειτικά διαφωτιστικό για το πως διαμορφώνεται το stack μετά από την διαχείριση μίας εξαίρεσης σε υψηλότερο επίπεδο.

Vector.hpp
#include <iostream>
#include <cstdlib>
using namespace std;
 
class Vector {
  int *array;
  int size;
 
public:
  Vector(int length=0);
  ~Vector();
};
Vector.cpp
#include "Vector.hpp"
 
Vector::Vector(int length) {
  cout << "Create vector of size: " << length << endl;
  size = length;
  array = new (nothrow) int[size];
  if(array==NULL) {
    cerr << "Memory allocation failure!" << endl;
    exit(-1);
  }
  for(int i=0; i<size; i++)
    array[i] = 0;
}
 
Vector::~Vector() {
  cout << "~Destroying vector of size: " << size << endl;
  delete [] array;
}
StackUnwinding.cpp
#include <iostream>
#include <cstdlib>
#include "Vector.hpp"
 
using namespace std;
 
// called by FFF()
void FFFF() {
  std::cout << "Start FFFF\n";
  Vector v(4);
  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";
  Vector v(3);
  FFFF();
  std::cout << "End FFF\n";
}
// called by F()
void FF() {
  std::cout << "Start FF\n";
  Vector v(2);
  try {
    FFF();
  } catch(char) { 
    std::cerr << "FF caught char exception\n";
  }
  std::cout << "End FF\n";
}
// called by main()
void F() {
  std::cout << "Start F\n";
  Vector v(1);
  try {
    FF();
  } catch (int) {
     std::cerr << "F caught int exception\n";
  } catch (char) {
     std::cerr << "F caught char 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;
}

Το αποτέλεσμα που εκτυπώνεται στην οθόνη είναι το εξής:

Start main
Start F
Create vector of size: 1
Start FF
Create vector of size: 2
Start FFF
Create vector of size: 3
Start FFFF
Create vector of size: 4
FFFF throwing int literal exception
~Destroying vector of size: 4
~Destroying vector of size: 3
~Destroying vector of size: 2
F caught int exception
End F
~Destroying vector of size: 1

Η εξέλιξη του program stack στο παρακάτω πρόγραμμα δίνεται στο παρακάτω διάγραμμα. Παρατηρήστε ότι το exception παράγεται στη συνάρτηση FFFF(), αλλά η διαχείριση του γίνεται στην F() πράγμα που συνεπάγεται την αυτόματη συρρίκνωση του stack στο επίπεδο της συνάρτησης F(). Μετά τη διαχείριση του exception, τα περιεχόμενα του stack για τις συναρτήσεις FFFF(), FFF()και FF() έχουν χαθεί.

Από τις εκτυπώσεις στην οθόνη, παρατηρήστε επίσης ότι όσα αντικείμενα έχουν δημιουργηθεί αυτόματα μέσα στο stack στις συναρτήσεις FF(), FFF(), FFFF() καταστρέφονται (με κλήση του αντίστοιχου καταστροφέα) και απελευθερώνεται η μνήμη που έχει δεσμευθεί για αυτά. Η διαδικασία καταστροφής των αντικειμένων γίνεται αυτόματα κατά τη διαδικασία του stack unwinding, ώστε να μην υπάρχουν απώλειες πόρων (memory leaks, περιγραφείς αρχείων ή sockets που παραμένουν ανοιχτά) μετά την διακοπή της εξαίρεσης.

cpp/stack_unwinding.txt · Last modified: 2023/05/15 14:13 by gthanos