Różnica: std :: runtime_error vs std :: wyjątek ()

127

Jaka jest różnica między std::runtime_errori std::exception? Jakie jest właściwe zastosowanie dla każdego z nich? Dlaczego przede wszystkim się różnią?

sivabudh
źródło

Odpowiedzi:

152

std::exceptionto klasa, której jedynym celem jest służenie jako klasa bazowa w hierarchii wyjątków. Nie ma innych zastosowań. Innymi słowy, koncepcyjnie jest to klasa abstrakcyjna (mimo że nie jest definiowana jako klasa abstrakcyjna w znaczeniu tego terminu w języku C ++).

std::runtime_errorJest to bardziej wyspecjalizowane klasy, z malejącym std::exception, ma być wrzucony w przypadku różnych uruchomieniowych błędów. Ma podwójny cel. To może być rzucony przez siebie, lub może służyć jako klasy bazowej do różnych, nawet bardziej wyspecjalizowanych typów wyjątków Runtime error, takich jak std::range_error, std::overflow_erroritd. Można definiować własne klasy wyjątków malejąco z std::runtime_error, jak można zdefiniować własny wyjątek klasy wywodzące się od std::exception.

Podobnie jak std::runtime_errorstandardowa biblioteka zawiera std::logic_error, również zstępującą z std::exception.

Celem takiej hierarchii jest zapewnienie użytkownikowi możliwości wykorzystania pełnej mocy mechanizmu obsługi wyjątków C ++. Ponieważ klauzula „catch” może wychwytywać wyjątki polimorficzne, użytkownik może napisać klauzule „catch”, które mogą przechwytywać typy wyjątków z określonego poddrzewa hierarchii wyjątków. Na przykład, catch (std::runtime_error& e)przechwyci wszystkie wyjątki z std::runtime_errorpoddrzewa, pozwalając wszystkim innym przejść (i przelecieć dalej w górę stosu wywołań).

PS Projektowanie użytecznej hierarchii klas wyjątków (która pozwoliłaby na wychwycenie tylko tych typów wyjątków, którymi jesteś zainteresowany w każdym punkcie twojego kodu) jest nietrywialnym zadaniem. To, co widzisz w standardowej bibliotece C ++, jest jednym z możliwych rozwiązań, które oferują Ci autorzy języka. Jak widać, zdecydowali się podzielić wszystkie typy wyjątków na „błędy czasu wykonywania” i „błędy logiczne”, a następnie zezwolić na tworzenie własnych typów wyjątków. Istnieją oczywiście alternatywne sposoby uporządkowania tej hierarchii, które mogą być bardziej odpowiednie w Twoim projekcie.

Aktualizacja: przenośność Linux vs Windows

Jak zauważyli Loki Astari i unixman83 w swojej odpowiedzi i komentarzach poniżej, konstruktor exceptionklasy nie przyjmuje żadnych argumentów zgodnie ze standardem C ++. Microsoft C ++ ma konstruktor pobierający argumenty w exceptionklasie, ale nie jest to standard. runtime_errorKlasa ma maksymalnie wykorzystać konstruktor argumentów ( char*) na obu platformach, Windows i Linux. Aby być przenośnym, lepiej używać runtime_error.

(I pamiętaj, tylko dlatego, że specyfikacja twojego projektu mówi, że twój kod nie musi działać w systemie Linux, nie oznacza to, że nigdy nie musi działać w systemie Linux).

Mrówka
źródło
1
Dziękuję Ci. świetna odpowiedź. chociaż zastanawiam się, czy kiedykolwiek istnieje potrzeba innego rodzaju wyjątku ... tylko myśl.
sivabudh
1
Jeśli istnieje możliwość, z której wyjątek można ponownie pokryć, wtedy inny typ wyjątku może być przydatny, ponieważ możemy użyć mechanizmu obsługi wyjątków, aby skierować wyjątek do programu obsługi, który spróbuje naprawić problem. Jeśli nie ma szans na wyzdrowienie, wystarczy jeden ze standardowych wyjątków.
Martin York
1
Na marginesie: nie ma nigdzie reguły, która zmusza cię do czerpania z tego std::exception. Jasne, wszystkie stdrzeczy rzucają klasy pochodne, ale nie ma absolutnie żadnego powodu, aby rzucać tylko std::exceptionobiekty pochodne.
rubenvb
1
@rubenvb Nie wiedziałem o tym, ale myślę, że wyczyści to kod do przyszłej obsługi, jeśli wrzucone zostaną tylko obiekty klas wywodzących się z wyjątku. Przykład: lubię dowiedzieć się, jakie niestandardowe wyjątki są zaimplementowane w mojej bazie kodu i szukać klas pochodzących z wyjątku.
this.myself
21

std::exceptionnależy wziąć pod uwagę (zwróć uwagę na rozważaną) abstrakcyjną podstawę standardowej hierarchii wyjątków. Dzieje się tak, ponieważ nie ma mechanizmu przekazywania określonej wiadomości (aby to zrobić, musisz wyprowadzić i wyspecjalizować what()). Nic nie stoi na przeszkodzie, abyś używał std :: wyjątek, aw przypadku prostych aplikacji może to być wszystko, czego potrzebujesz.

std::runtime_errorz drugiej strony ma prawidłowe konstruktory, które akceptują ciąg znaków jako wiadomość. Gdy what()jest wywoływana, zwracany jest wskaźnik const char, który wskazuje na łańcuch w języku C, który ma taki sam ciąg, jaki został przekazany do konstruktora.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 
Martin York
źródło
1
Dzięki za odpowiedź Martin. Jednak używam std :: wyjątek () w taki sam sposób, jak opisano powyżej. tj. konstruktor std ::ception () może również przyjmować std :: string () lub const char *.
sivabudh
14
Nie zgodnie ze standardem. std :: wyjątek ma jeden konstruktor, który nie przyjmuje żadnych argumentów. Używanie wersji, która akceptuje std :: string lub C-String, nie jest przenośne.
Martin York
10
Dzięki Microsoftowi przyzwyczaiłem się do rzucania std::exception(std::string). Teraz zdaję sobie sprawę, że muszę wrzucić, std::runtime_errorjeśli chcę, aby mój kod działał w systemie Linux (GCC).
unixman83