Udostępnij za pośrednictwem


Wyjątki: zwalnianie obiektów w wyjątkach

W tym artykule wyjaśniono potrzebę i metodę zwalniania obiektów w przypadku wystąpienia wyjątku. Tematy obejmują:

Wyjątki zgłaszane przez platformę lub przez aplikację przerywają normalny przepływ programu. W związku z tym bardzo ważne jest zachowanie ścisłego śledzenia obiektów, dzięki czemu można je prawidłowo usunąć w przypadku zgłoszenia wyjątku.

W tym celu należy wykonać dwie podstawowe metody.

  • Obsługa wyjątków lokalnie przy użyciu słów kluczowych icatch, a następnie zniszczenie wszystkich obiektów za pomocą try jednej instrukcji.

  • Przed zgłoszeniem wyjątku catch poza blokiem w celu dalszej obsługi należy zniszczyć dowolny obiekt w bloku.

Te dwa podejścia przedstawiono poniżej jako rozwiązania następującego problematycznego przykładu:

void SomeFunc()        // Problematic code
{
   CPerson* myPerson = new CPerson;

   // Do something that might throw an exception.
   myPerson->SomeFunc();

   // Now destroy the object before exiting.
   // If SomeFunc above throws an exception this code will
   // not be reached and myPerson will not be deleted.
   delete myPerson;
}

Zgodnie z powyższym zapisem nie zostanie usunięty, myPerson jeśli wyjątek zostanie zgłoszony przez polecenie SomeFunc. Wykonanie przechodzi bezpośrednio do następnego zewnętrznego programu obsługi wyjątków, pomijając normalne działanie funkcji i kod, który usuwa obiekt. Wskaźnik do obiektu wykracza poza zakres, gdy wyjątek opuszcza funkcję, a pamięć zajmowana przez obiekt nigdy nie zostanie odzyskana, o ile program jest uruchomiony. Jest to przeciek pamięci; zostanie wykryta przy użyciu diagnostyki pamięci.

Obsługa wyjątku lokalnie

Model try/catch zapewnia defensywną metodę programowania umożliwiającą uniknięcie przecieków pamięci i zapewnienie, że obiekty są niszczone w przypadku wystąpienia wyjątków. Na przykład przykład przedstawiony wcześniej w tym artykule może zostać przepisany w następujący sposób:

void SomeFunc()
{
   CPerson* myPerson = new CPerson;

   try
   {
      // Do something that might throw an exception.
      myPerson->SomeFunc();
   }
   catch (CException* e)
   {
      // Handle the exception locally
      e->Delete();
   }

   // Now destroy the object before exiting.
   delete myPerson;
}

W tym nowym przykładzie skonfigurowana jest procedura obsługi wyjątków w celu przechwycenia wyjątku i obsługi go lokalnie. Następnie zamyka funkcję normalnie i niszczy obiekt. Ważnym aspektem tego przykładu jest to, że kontekst do przechwycenia wyjątku jest ustanawiany przy użyciu bloków try/catch . Bez lokalnej ramki wyjątku funkcja nigdy nie wiedziałaby, że wyjątek został zgłoszony i nie będzie miał szans na wyjście normalnie i zniszczenie obiektu.

Zgłaszanie wyjątków po zniszczeniu obiektów

Innym sposobem obsługi wyjątków jest przekazanie ich do następnego zewnętrznego kontekstu obsługi wyjątków. catch W bloku możesz wykonać czyszczenie obiektów przydzielonych lokalnie, a następnie zgłosić wyjątek w celu dalszego przetwarzania.

Funkcja throwing może lub nie musi cofnąć przydziału obiektów stert. Jeśli funkcja zawsze cofa przydział obiektu sterta przed zwróceniem w normalnym przypadku, funkcja powinna również cofnąć przydział obiektu sterta przed zgłoszeniem wyjątku. Z drugiej strony, jeśli funkcja zwykle nie cofa przydziału obiektu przed zwróceniem w normalnym przypadku, musisz zdecydować na podstawie wielkości liter, czy obiekt sterty powinien zostać cofnięty.

W poniższym przykładzie pokazano, jak można wyczyścić obiekty przydzielone lokalnie:

void SomeFunc()
{
   CPerson* myPerson = new CPerson;

   try
   {
      // Do something that might throw an exception.
      myPerson->SomeFunc();
   }
   catch (CException* e)
   {
      e->ReportError();
      // Destroy the object before passing exception on.
      delete myPerson;
      // Throw the exception to the next handler.
      throw;
   }

   // On normal exits, destroy the object.
   delete myPerson;
}

Mechanizm wyjątku automatycznie cofa przydział obiektów ramek; destruktor obiektu ramki jest również wywoływany.

Jeśli wywołasz funkcje, które mogą zgłaszać wyjątki, możesz użyć bloków try/catch , aby upewnić się, że przechwytujesz wyjątki i masz szansę zniszczyć wszystkie utworzone obiekty. W szczególności należy pamiętać, że wiele funkcji MFC może zgłaszać wyjątki.

Aby uzyskać więcej informacji, zobacz Wyjątki: przechwytywanie i usuwanie wyjątków.

Zobacz też

Obsługa wyjątków