[C++] Wyjątek w konstruktorze, zachowanie programu

wawek91
Użytkownik
Użytkownik
Posty: 795
Rejestracja: 2 cze 2010, o 08:56
Płeć: Mężczyzna
Lokalizacja: Tarnów
Podziękował: 14 razy
Pomógł: 66 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: wawek91 »

Kod: Zaznacz cały

class A
{
 public:
        virtual void f(){cout << "A.f";}
        ~A(){f();}   
};

class B: public A
{
 A a;
 public:
        void f(){cout << "B.f";}
        B(){throw -1;}
        ~B(){f();}      
};

int main()
{
 try
 {
  B b;
 }catch(...){cout << " Exc ";}  
 getchar();
 return 0;
}
Pytanie, co się wypiszę i dlaczego. Po uruchomieniu wypisuję się

Kod: Zaznacz cały

A.fA.f Exc 
Moje pytanie brzmi czemu? Bo rozumiem, że destruktor klasy B nie zostanie wywołany, ponieważ konstruktor wyrzuca wyjątek przez co obiekt nie jest jakby do końca utworzony. Jednak czemu dwukrotnie wywoła się destruktor klasy bazowej? Raz pewnie dla obiektu wewnątrz klasy tak? A drugi raz? Czemu wywoła się skoro nie wywoła się najpierw destruktor klasy pochodnej?
Ostatnio zmieniony 21 cze 2011, o 11:17 przez Afish, łącznie zmieniany 1 raz.
Powód: Staraj się lepiej dobierać nazwy tematów, tak by wskazywały o czym jest treść zadania.
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: Afish »

Najpierw jest tworzony obiekt klasy A, który niejawnie zawiera obiekt klasy B. Potem jest tworzony obiekt klasy A, który jest jednym z pól klasy B. Gdy poleci wyjątek, nie wywołuje się destruktor obiektu b, bo obiekt nie został do końca utworzony (dlatego rzucanie wyjątków z konstruktorów i destruktorów jest śliską sprawą). Następuje odwinięcie stosu, obiekt b zaczyna być kasowany. Wywołują się destruktory obiektów od końca, czyli najpierw zniknie pole a klasy B, a potem niejawnie obiekt klasy A, który zawiera klasa B. Stąd dwa destruktory.
wawek91
Użytkownik
Użytkownik
Posty: 795
Rejestracja: 2 cze 2010, o 08:56
Płeć: Mężczyzna
Lokalizacja: Tarnów
Podziękował: 14 razy
Pomógł: 66 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: wawek91 »

Kod: Zaznacz cały

class A
{
 public:
        virtual void f(){cout << "A.f";}
        ~A(){f();}      
};

class B: public A
{
 public:
        void f(){cout << "B.f";}
        B(){throw 0;}
        ~B(){f();}      
};

int main()
{
 try
 {
  B* ptr = new B();
  delete ptr;         
 }catch(...){cout << " Exc ";} 
 
 getchar();
 return 0;  
}
Czyli w tym przypadku podobnie. Tworzony jest obiekt klasy A, który niejawnie zawiera obiekt klasy B. Potem wyskoczy wyjątek, który zostanie wyłapany także instrukcja

Kod: Zaznacz cały

delete ptr
zostanie ominięta. Wtedy zostanie wywołany destruktor klasy A a nastepnię obsługa wyjątku stąd wyświetli się

Kod: Zaznacz cały

A.f Exc
Dobrze zrozumiałem?
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: Afish »

Tak. A żeby jeszcze sprecyzować, to mówiąc "Najpierw jest tworzony obiekt klasy A, który niejawnie zawiera obiekt klasy B" mam na myśli to, że to we wnętrzu obiektu klasy B siedzi obiekt klasy A. To tak na wszelki wypadek, gdyby ktoś to zinterpretował odwrotnie.
wawek91
Użytkownik
Użytkownik
Posty: 795
Rejestracja: 2 cze 2010, o 08:56
Płeć: Mężczyzna
Lokalizacja: Tarnów
Podziękował: 14 razy
Pomógł: 66 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: wawek91 »

Kod: Zaznacz cały

class A
{
 public:
        virtual void f(){cout << "A.f";}
        ~A(){f();}     
};

class B:public A
{
 public:
        void f(){cout << "B.f";}
        ~B(){f();}      
};

B b;
int main()
{
    A*a = new B();
    delete a;
    cout << "M";
    
    getchar();
    return 0;
}
Jeszcze taki przypadek. To że przy wyjściu z programu wypisze się

Kod: Zaznacz cały

B.fA.f
to się domysliłem ponieważ wtedy będzie niszczony obiekt klasy B w którym siedzi obiekt klasy A. Natomiast zanim to nastąpi wypisuje się

Kod: Zaznacz cały

A.fM
I tu nie mam pojęcia co następuje.
Afish
Moderator
Moderator
Posty: 2828
Rejestracja: 15 cze 2008, o 15:45
Płeć: Mężczyzna
Lokalizacja: Seattle, WA
Podziękował: 3 razy
Pomógł: 356 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: Afish »

Najpierw dynamicznie tworzysz obiekt klasy B i go niszczysz. Ponieważ wskazujesz na niego przez wskaźnik do klasy A, a destruktor nie jest wirtualny, zatem wywoła się tylko destruktor z klasy A. Następnie wypisuje się normalnie M. Potem po zakończeniu funkcji main niszczony jest obiekt globalny klasy B, a wraz z nim wewnętrzny obiekt klasy A.
wawek91
Użytkownik
Użytkownik
Posty: 795
Rejestracja: 2 cze 2010, o 08:56
Płeć: Mężczyzna
Lokalizacja: Tarnów
Podziękował: 14 razy
Pomógł: 66 razy

[C++] Wyjątek w konstruktorze, zachowanie programu

Post autor: wawek91 »

Faktycznie, mój błąd nie zauważyłem, że destruktor nie jest wirtualny.
ODPOWIEDZ