Sytuacja wyjątkowa może zdarzyć się podczas wykonywania konstruktora lub destruktora. Taka sytuacja jest szczególnie trudna do właściwej obsługi. Powiedzmy zatem o kilku sprawach, o których trzeba wtedy pamiętać.
Jeśli wyjątek został zgłoszony podczas konstrukcji obiektu, to
obiekt ten nie powstanie, jego destruktor nie zostanie wywołany, a
wszystkie do tej pory utworzone składowe zostaną usunięte. Mogą
to być już utworzone składowe obiektowe: dla nich destruktory
zostaną wywołane. Oczywiście powstanie kłopot, jeśli są
w klasie składowe wskaźnikowe, a same obiekty, na które one
wskazują, zostały w konstruktorze zaalokowane na stercie lub odnoszą
się do zasobów systemowych, jak np. plików. Tego typu obiekty są
zwykle usuwane (zwalniane) w destruktorze, ale on nie zadziała. W ten
sposób, w razie wystąpienia sytuacji wyjątkowej, nieudany obiekt
zostanie co prawda usunięty, ale zasoby (pamięć, otwarte pliki) nie
zostaną zwolnione. Można temu zaradzić „opakowując” tego rodzaju
składowe wskaźnikowe tak, aby uczynić z nich obiekty, dla których
w razie niepowodzenia wywołany zostanie destruktor zwalniający zasoby.
Rozpatrzmy przykład:
      1.  #include <iostream>
      2.  #include <cstring>
      3.  #include <cstdio>  // FILE, fopen, fclose
      4.  using namespace std;
      5.  
      6.  class A {
      7.      struct nazw {
      8.          char* n;
      9.          nazw(const char* n)
     10.              : n(strcpy(new char[strlen(n)+1],n))
     11.          { }
     12.          ~nazw() {
     13.              cerr << "dtor nazw: " << n << endl;
     14.              delete [] n;
     15.          }
     16.      };
     17.  
     18.      nazw Nazwisko;
     19.      FILE*    plik;
     20.  public:
     21.      A(const char* n, const char* p)
     22.          : Nazwisko(n)
     23.      {
     24.          plik = fopen(p,"r");
     25.          // ...
     26.  //      throw 1;
     27.          // ...
     28.      }
     29.  
     30.      // inne pola i metody
     31.  
     32.      ~A() {
     33.          cerr << "dtor A" << endl;
     34.          if (plik) fclose(plik);
     35.      }
     36.  };
     37.  
     38.  int main() {
     39.      try {
     40.          A a("Kowalski","zasob.cpp");
     41.      } catch(...) {
     42.          cerr << "Nie udalo sie skonstruowac obiektu\n";
     43.      }
     44.  }
Prócz nazwiska, klasa A zawiera pole wskaźnikowe wskazujące obiekt typu FILE (jest to standardowy typ w czystym C opisujący pliki).
Załóżmy, że linia 26 (throw 1) jest wykomentowana. Konstruktor klasy A inicjuje składowe opisujące nazwisko i kończy się prawidłowo. Żaden wyjątek nie został zgłoszony. Po wyjściu sterowania z ciała bloku try obiekt klasy A, jako obiekt lokalny dla tego bloku, jest usuwany i wywoływany jest jego destruktor zamykający plik. Następnie usuwane są obiekty składowe i wywoływane są ich destruktory, a więc w naszym przypadku usunięty będzie obiekt Nazwisko, a w jego destruktorze zwolniona zostanie pamięć na nazwisko. Wydruk programu
    dtor A
    dtor nazw: Kowalski
świadczy o tym, że obiekt 
a
 został prawidłowo
usunięty.
Spróbujmy teraz uaktywnić linię 26, która powoduje powstanie sytuacji wyjątkowej w trakcie wykonywania konstruktora. Teraz wydruk z programu to
    dtor nazw: Kowalski
    Nie udalo sie skonstruowac obiektu
Po powstaniu wyjątku destruktor klasy 
A
 dla powstającego
obiektu nie został wywołany. Tak więc plik, choć już otwarty,
nie został zamknięty — przepadł tylko wskaźnik do niego.
Natomiast napis zawierający nazwisko został prawidłowo usunięty!
Stało się tak, bo powstanie wyjątku spowodowało wywołanie
destruktorów dla już utworzonych składowych obiektowych, a więc
dla składowej
Nazwisko.
W przykładzie powyższym nie wyłapywaliśmy wyjątku powstającego podczas konstruowania obiektu w samym konstruktorze, ale pozwoliliśmy mu wyjść poza konstruktor, gdzie był przechwytywany w funkcji main. Inna jest sytuacja z wyjątkami, jakie mogą powstać w trakcie wykonania destruktora. Problem polega na tym, że destruktor, jak mówiliśmy, może zostać wywołany podczas zwijania stosu w poszukiwaniu procedury obsługi innego wyjątku. Powstanie dodatkowego nieobsłużonego wyjątku w destruktorze powodowałoby „podwójne” zwijanie stosu. Taka sytuacja nie jest w C++ możliwa; jeśli powstanie, program jest natychmiast kończony za pomocą funkcji terminate. Tak więc, jeśli jakikolwiek wyjątek może być zgłoszony podczas wykonywania destruktora, to należy go obsłużyć — przechwycić odpowiednią frazą catch — wewnątrz tego destruktora, nie dopuszczając do jego „ucieczki”.
T.R. Werner, 21 lutego 2016; 20:17