2015-09-01 14 views
6

Czy otrzymamy wtedy UB? Próbowałem to:Co się stanie, jeśli konstruktor zgłasza wyjątek?

#include <iostream> 

struct B 
{ 
    B(){ std::cout << "B()" << std::endl; } 
    ~B(){ std::cout << "~B()" << std::endl; } 
}; 

struct A 
{ 
    B b; 
    A(){ std::cout << "A()" << std::endl; throw std::exception(); } 
    ~A(){ std::cout << "~A()" << std::endl; } 
}; 

int main() 
{ 
    A a; 
} 

desctructor nie został wezwany do netither A ani B. Rzeczywista moc:

B() 
A() 
terminate called after throwing an instance of 'std::exception' 
    what(): std::exception 
bash: line 7: 21835 Aborted     (core dumped) ./a.out 

http://coliru.stacked-crooked.com/a/9658b14c73253700

Więc za każdym razem konstruktor rzuca podczas inicjalizacji zmiennych zakresu bloku, mamy dostać UB?

+2

Wyrzuciłeś wyjątek i go nie złapałeś, więc program się zakończył. Co sprawia, że ​​myślisz, że to UB? – Beta

Odpowiedz

15

Nie, wyrzucenie wyjątku jest najlepszym sposobem zasygnalizowania błędu podczas konstruowania obiektu. (. Ponieważ nie ma wartości powrotu, nie ma innego wyjścia, inne niż konstruowanie bezgłowe obiekt, który jest zły styl w C++)

Od samego człowieka, Bjarne Stroustrup: http://www.stroustrup.com/bs_faq2.html#ctor-exceptions

Re: „Ale mój destruktor nie został nazwany "

Rzeczywiście. W C++ mówi się, że okres istnienia obiektu rozpoczyna się, gdy konstruktor zostanie ukończony. I kończy się zaraz po wywołaniu destruktora. Jeśli ctor rzuca, to dtor nie jest wywoływany.

(Ale dtors wszelkich obiektów zmiennych członkiem, których ctors już prowadził do zakończenia przed ten Ran konstruktor, nazywane są).

należy skonsultować się standardem, czy dobry podręcznik więcej szczegółów esp. związane z tym, co dzieje się, gdy w grę wchodzi dziedziczenie. Jako ogólna zasada, destruktory są wywoływane w odwrotnej kolejności budowy.

Twoje pytanie o to, dlaczego "~ B" nie zostało wywołane w twoim konkretnym kodzie, to dlatego, że nie złapałeś wyjątku w main. Jeśli zmienisz swój kod tak, aby główny przechwycił wyjątek, zostanie wywołany "~ B()". Kiedy jednak zostanie zgłoszony wyjątek, który nie ma żadnego haczyka, implementacja może zakończyć program bez wywoływania destruktorów lub niszczenia statycznie zainicjowanych obiektów.

odniesienia w standardowej C++ 11 (nacisk kopalni)

15.5.1 :: rozwiązać std() funkcja [except.terminate]

W niektórych sytuacje obsługa wyjątków musi zostać porzucona dla mniej subtelnych technik obsługi błędów.

...

W takich przypadkach, std :: terminate() jest wywoływana (18.8.3). W sytuacji, gdy nie znaleziono zgodnego programu obsługi, jest on definiowany przez implementację niezależnie od tego, czy stos jest rozwijany przed wywołaniem funkcji std :: terminate().

+0

Ale destruktor nie został wywołany dla obiektu konstruktora (B b) ... – stella

+0

__Musisz skonsultować się ze standardem lub dobrym podręcznikiem po więcej szczegółów .__ Zrobiłem 6,7/4, jedyne co mogłem znaleźć to: __Jeśli inicjalizacja kończy się przez wyrzucenie wyjątku, inicjalizacja nie jest kompletna, więc zostanie wypróbowana ponownie, gdy następna kontrola przejdzie do deklaracji .__ – stella

+0

Postaram się znaleźć odniesienie, jeśli chodzi o implementację wolną, aby nie niszczyć rzeczy, gdy nie ma przechwyconego wyjątku występuje –

3

Zgłaszanie wyjątków w konstruktorze jest standardowym sposobem obsługi błędów i nie jest niezdefiniowanym zachowaniem. Jeśli wrzucisz konstruktor, zakłada się, że obiekt nie został poprawnie zainicjowany, więc jego destruktor nie jest wywoływany.

+1

Ale" B b "było. Powinien to być destruktor, prawda? – stella

Powiązane problemy