2012-06-08 16 views
86

patrząc na niektóre kodu Natknąłem się na:throw new std :: exception vs throw std :: exception

throw /*-->*/new std::exception ("//... 

a ja zawsze myślałem, że nie trzeba/nie powinno się używać new tutaj.
Jaki jest właściwy sposób, są zarówno OK, jeśli tak jest jakaś różnica?

BTW z tego co widzę, podczas gdy „grepping” z PowerShell przypominającego bibliotekami nigdy używać throw new.

P.S. również znalazłem kod CLI, który używa throw gcnew. Czy to w porządku?

+0

Myślę, że "throw gcnew" przydałoby się np. jeśli chcesz, aby kod zarządzany przechwytywał twój wyjątek. Czy ktoś może mi to poprawić? – jpalecek

+1

.Net zajmuje się wyjątkami za pomocą wskaźnika, więc polecenie gcnew jest właściwym rozwiązaniem. –

+1

@SebastianRedl .Net "wskaźnik" może być niejednoznaczny? Chociaż gcnew na pewno nie jest. 'System :: Exception' jest ogólnie odniesieniem do zarządzanego obiektu na stadzie zbierającym śmieci. Zawsze byłem rzucany przez 'gcnew' i złapany przez' System :: Exception^'. Oczywiście używam 'finally' przez cały czas w C++/CLI, chociaż nie często łączę się z wyjątkami C++ w tym samym bloku' try', nie jestem pewien dlaczego. –

Odpowiedz

72

Konwencjonalny sposób rzut złapać wyjątków jest rzut obiektu wyjątku i złapać ją odniesienia (zwykle const odniesienia). Język C++ wymaga, aby kompilator generował odpowiedni kod w celu skonstruowania obiektu wyjątku i właściwego czyszczenia go we właściwym czasie.

rzucanie wskaźnik do dynamicznie przydzielonego obiektu nigdy nie jest dobrym pomysłem. Wyjątki mają na celu umożliwienie pisania bardziej odpornego kodu w obliczu błędów. Jeśli rzucasz obiekt wyjątkowy w konwencjonalny sposób, możesz być pewien, że niezależnie od tego, czy zostanie on złapany przez klauzulę catch nazwaną właściwym typem, przez catch (...), czy zostanie on ponownie zgłoszony, czy nie, zostanie odpowiednio zniszczony we właściwym czasie. . (Jedynym wyjątkiem jest sytuacja, w której nigdy nie zostanie złapany, ale jest to sytuacja nie do naprawienia niezależnie od tego, jak na nią patrzysz.)

Jeśli rzucisz wskaźnik na dynamicznie przydzielany obiekt, musisz mieć pewność, że stos wywołań wygląda tak, jak w punkcie, w którym chcesz rzucić wyjątek, znajduje się blok catch, który nazywa właściwy typ wskaźnika i ma odpowiednie wywołanie delete.Twój wyjątek nigdy nie może zostać przechwycony przez catch (...), chyba że ten blok ponownie rzuci wyjątek, który następnie zostanie przechwycony przez inny blok catch, który zajmuje się tym wyjątkiem.

Oznacza to, że skorzystałeś z funkcji obsługi wyjątków, która powinna ułatwić pisanie niezawodnego kodu i bardzo utrudnić pisanie kodu, który jest poprawny we wszystkich sytuacjach. Pozostawia to poza kwestią, że prawie niemożliwe będzie działanie jako kod biblioteki dla kodu klienta, który nie będzie oczekiwał tej funkcji.

+1

"wyrzuć stos wyjątków" lub sterty mojego przyjaciela? Stos lub kupa? (Może szukałem gdzieś złego globalnego przykładu) no i jeśli stos, to jaki jest odpowiedni zakres? –

+0

@ebyrob: Nie jestem do końca pewien, o co pytasz, ale brzmi to tak, jakbyś chciał wiedzieć o pamięci i/lub czasie życia obiektu wyjątku, na który można odpowiedzieć [tutaj] (http://stackoverflow.com/questions/1654150/scope-of-exception-object-in-c). Jeśli nie, lepiej byłoby zadać osobne pytanie. –

26

Nie ma potrzeby korzystania new kiedy rzuca wyjątek.

Wystarczy napisać:

throw yourexception(yourmessage); 

i złapać jak:

catch(yourexception const & e) 
{ 
     //your code (probably logging related code) 
} 

Zauważ, że yourexception powinny pochodzić bezpośrednio lub pośrednio z std::exception.

+5

Dlaczego? dlaczego nie użyć "nowego"? dlaczego wyprowadzić 'yourexception' z' std :: exception'? – Walter

+0

Kiedy jestem leniwy (co jest często używane), dlaczego nie 'throw std :: exception;' work? g ++ nie będzie go kompilował ... –

+5

@ebyrob: 'std :: exception' jest typem, a ty nie możesz rzucić * typu *, musisz rzucić * obiekt *. Tak więc składnia powinna wyglądać tak: 'throw std :: exception();' To skompiluje. Teraz, jak to dobrze, jest zupełnie inne pytanie. – Nawaz

21

Throwing new std::exception jest poprawny, jeśli strona połączenia oczekuje na złapanie std::exception*. Ale nikt nie spodziewa się, że złapie wskaźnik do wyjątku. Nawet jeśli udokumentować to, co się robi i funkcja osoby zapoznać się z dokumentacją, są one nadal mogą zapomnieć i spróbować złapać odniesienie do std::exception obiektu zamiast.

+25

Rzucanie 'new std :: exception' jest poprawne tylko wtedy, gdy strona wywoławcza spodziewa się przechwycić wskaźnik ORAZ oczekuje przejęcia zarządzania wyjątkiem alokacji ORAZ nigdy nie będzie żadnych przypadków, w których funkcja będzie wywoływana przez coś, co nie przechwytuje bezpośrednio poprawnego wskaźnika ("catch (...)" lub w ogóle nie ma obsługi) w przeciwnym razie nastąpi przeciek obiektu. W skrócie można to określić w przybliżeniu jako "nigdy". –

+0

Ciekawe, w jaki sposób ta odpowiedź została zaakceptowana, kiedy naprawdę jest to @ komentarz * Charlesa *, który jest poprawną odpowiedzią. –

+0

@John: To też przyszło mi do głowy. Ale myślę, że ten drugi cios ma dobry wpływ na moje suche podsumowanie i Charles śmieje się, rozszerzając na różne sposoby, na jakie ludzie są w stanie zapomnieć, aby poradzić sobie z tym prawidłowo. Szkoda, że ​​nie zyskujesz reputacji z głosujących w górę komentarzy. – Hurkyl

7

C++ FAQ ma ładny dyskusję na ten temat.

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

zasadzie „chyba nie jest dobry powód, aby nie, łapać przez odniesienie Unikać łapania przez wartość, ponieważ powoduje to wykonanie kopii, a kopia może mieć inne zachowanie od tego, co zostało rzucone, tylko w wyjątkowych okolicznościach powinnaś złapać wskaźnik. "

+2

Jak zwykle, FAQ jest źle sformułowane. Możesz złapać według wartości lub referencji. Wskaźnik jest po prostu wartością (którą przechwytujesz według wartości lub odniesienia). Pamiętaj, że typ 'A' różni się od typu' A * ', więc jeśli zrobię' throw A() 'nie mogę złapać' catch (A * e) ', ponieważ jest to zupełnie inny typ. –

+0

Te linki są teraz uszkodzone. – spanndemic

+1

Naprawiłem linki @spanndemic – user1202136

Powiązane problemy