patrząc na kod, na który natknąłem się:
throw /*-->*/new std::exception ("//...
i zawsze myślałem, że nie potrzebujesz / nie powinieneś new
tutaj używać .
Jaki jest właściwy sposób, czy oba są w porządku, a jeśli tak, to czy jest jakaś różnica?
BTW z tego, co widzę podczas "grepping" z PowerShell Boost, biblioteki nigdy nie używają throw new
.
PS również znalazłem kod CLI, który używa throw gcnew
. Czy to w porządku?
throw gcnew
przydałoby się np. jeśli chcesz, aby kod zarządzany przechwytywał Twój wyjątek. Czy ktoś może mnie w tym poprawić?System::Exception
jest ogólnie odwołaniem do zarządzanego obiektu na stercie zbierania elementów bezużytecznych. Zawsze rzucałemgcnew
i łapałemSystem::Exception ^
. Oczywiściefinally
cały czas używam również w C ++ / CLI, chociaż nie często mieszam się z wyjątkami C ++ w tym samymtry
bloku, nie jestem pewien dlaczego.Odpowiedzi:
Konwencjonalnym sposobem zgłaszania i przechwytywania wyjątków jest zgłoszenie obiektu wyjątku i przechwycenie go przez odwołanie (zwykle
const
odwołanie). Język C ++ wymaga, aby kompilator wygenerował odpowiedni kod, aby skonstruować obiekt wyjątku i odpowiednio go wyczyścić w odpowiednim czasie.Rzucanie wskaźnika do dynamicznie przydzielanego obiektu nigdy nie jest dobrym pomysłem. Wyjątki mają umożliwić pisanie bardziej niezawodnego kodu w obliczu błędów. Jeśli wyrzucisz obiekt wyjątku w konwencjonalny sposób, możesz być pewien, że niezależnie od tego, czy zostanie przechwycony przez klauzulę catch z nazwą poprawnego typu, przez a
catch (...)
, czy zostanie następnie ponownie wyrzucony, czy nie, zostanie poprawnie zniszczony w odpowiednim czasie. (Jedynym wyjątkiem jest sytuacja, w której nigdy nie zostanie złapany, ale jest to sytuacja niemożliwa do odzyskania, niezależnie od tego, jak na to spojrzysz).Jeśli rzucasz wskaźnik do dynamicznie przydzielanego obiektu, musisz być pewien, że niezależnie od tego, jak wygląda stos wywołań w miejscu, w którym chcesz zgłosić wyjątek, istnieje blok catch, który nazywa właściwy typ wskaźnika i ma odpowiednie
delete
wywołanie. Twój wyjątek nigdy nie może zostać przechwycony,catch (...)
chyba że ten blok ponownie wyrzuci wyjątek, który jest następnie przechwytywany przez inny blok catch, który poprawnie radzi sobie z wyjątkiem.W rzeczywistości oznacza to, że skorzystałeś z funkcji obsługi wyjątków, która powinna ułatwić pisanie solidnego kodu i bardzo utrudniłaby pisanie kodu, który byłby poprawny we wszystkich sytuacjach. Pomija to problem, że prawie niemożliwe będzie działanie jako kod biblioteki dla kodu klienta, który nie będzie oczekiwał tej funkcji.
źródło
Nie ma potrzeby używania
new
podczas zgłaszania wyjątku.Tylko napisz:
i złap jako:
Zauważ, że
yourexception
powinno pochodzićstd::exception
bezpośrednio lub pośrednio.źródło
new
? dlaczego pochodzićyourexception
zstd::exception
?throw std::exception;
działa? g ++ nie wydaje się go skompilować ...std::exception
jest typem i nie możesz rzucić typu , musisz rzucić obiekt . Więc składnia powinna wyglądać następująco:throw std::exception();
To się skompiluje. Jak to dobrze, to zupełnie inna kwestia.Zgłaszanie
new std::exception
jest poprawne, jeśli strona wywołująca spodziewa się złapaćstd::exception*
. Ale nikt nie będzie oczekiwał, że złapie wskaźnik do wyjątku. Nawet jeśli udokumentujesz to, co robi twoja funkcja, a ludzie przeczytają dokumentację, nadal mogą zapomnieć istd::exception
zamiast tego próbują złapać odniesienie do obiektu.źródło
new std::exception
jest poprawne tylko wtedy, gdy witryna wywołania oczekuje przechwycenia wskaźnika ORAZ oczekuje przejęcia zarządzania wyjątkiem alokacji ORAZ nigdy nie będzie przypadków, w których funkcja zostanie wywołana przez coś, co nie jest jawnie przechwytywane prawidłowy wskaźnik (catch(...)
lub brak obsługi), w przeciwnym razie nastąpi wyciek obiektu. Krótko mówiąc, można to w przybliżeniu określić jako „nigdy”.C ++ FAQ zawiera ciekawą dyskusję na ten temat:
Zasadniczo „chyba, że nie ma dobrego powodu, aby tego nie robić, łapać przez odniesienie. Unikaj łapania według wartości, ponieważ powoduje to utworzenie kopii, a kopia może zachowywać się inaczej niż to, co zostało rzucone. Tylko w bardzo szczególnych okolicznościach należy łapać za pomocą wskaźnika. "
źródło
A
różni się od typu,A*
więc jeśli to zrobięthrow A()
, NIE mogę go złapać,catch(A* e)
ponieważ jest to zupełnie inny typ.Operator nowy nie może zagwarantować, że nigdy nie zgłosi wyjątku. Z tego powodu użycie go do wyrzucenia „prawidłowego” (zamierzonego) wyjątku spowodowałoby powstanie kodu, którego nie można zagwarantować, że nie ulegnie awarii. Ponieważ w danym momencie może występować tylko jeden wyjątek, a program próbuje zgłosić dwa, zanim którykolwiek z nich zostanie przechwycony, najlepszą rzeczą, jaką może zrobić implementacja, jest natychmiastowe przerwanie programu, np. Przez wywołanie std :: terminate.
źródło