Nie używaj wyjątków w destruktorze

Objawy: program się gwałtownie wywala, niekiedy w zrzucie stosu można się dopatrzeć informacji o wywołaniu funkcji terminate, na Unixach mamy informację o SIGABORT (sygnale 134).

Większość takich błędów jest spowodowana rzuceniem wyjątku przez destruktor jakiegoś obiektu, który to destruktor został zawołany w czasie zwijania kontekstu, gdy "leciał" już inny wyjątek.

Innymi słowy, kod:

class A
{
public:
    ~A()
    {
        throw "aaa";
    }  
};

void main()
{
    try 
    {
        A a;
        throw "bbb";
    } 
    catch(const char *s) 
    {
        cout << "Exception " << s << endl;
    }
}

skończy się SIGABORT'em i core, bo w czasie zwijania kontekstu po rzuceniu "bbb" z destruktora A poleci "aaa".

Sytuacji takich nie da się wykluczyć, jeśli pozwalamy na wyjątki rzucane z destruktorów. Po prostu: destruktor nigdy nie może rzucić wyjątku. Nie wolno mu. Może coś zalogować, ustawić jakieś flagi, zrobić cokolwiek - ale nie rzucać wyjątek.

Przy okazji: analogiczne objawy ma wystąpienie wyjątku, który nigdzie nie został złapany. W main-ie z zasady umieszczamy kod, który łapie wszelkie możliwe i niemożliwe typy wyjątków - ale gdy o tym zapomnimy, możemy nie skojarzyć tej najprostszej

możliwości.

komentarze obsługiwane przez Disqus