Czy powinienem używać specyfika WYJĄTKÓW w C++?

W C++ można określić, że funkcja może lub nie może wyrzucić wyjątku, używając określenia wyjątku. Na przykład:

void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type

Mam wątpliwości co do ich używania, ponieważ:

  1. kompilator tak naprawdę nie wymusza specyfików WYJĄTKÓW w żaden rygorystyczny sposób, więc korzyści nie są wielkie. Najlepiej, jeśli chcesz uzyskać błąd kompilacji.
  2. Jeśli funkcja narusza specyfikator wyjątku, myślę, że standardowym zachowaniem jest zakończenie program.
  3. W VS.Net, traktuje throw (X) jako throw (...), więc przestrzeganie normy nie jest silne.

Czy uważasz, że należy używać specyfików WYJĄTKÓW?
Proszę odpowiedzieć "tak" lub " nie " i podać kilka powodów, aby uzasadnić swoją odpowiedź.

Author: iammilind, 2008-09-18

14 answers

Nie.

Oto kilka przykładów dlaczego:

  1. Kod szablonu jest niemożliwy do napisania z wyjątkiem specyfikacji,

    template<class T>
    void f( T k )
    {
         T x( k );
         x.x();
    }
    

    Kopie mogą rzucać, parametr passing może rzucać, a x() może rzucać jakiś nieznany wyjątek.

  2. Wyjątek-specyfikacje zazwyczaj zabraniają rozszerzalności.

    virtual void open() throw( FileNotFound );
    

    Może ewoluować w

    virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );
    

    Naprawdę można by to napisać jako

    throw( ... )
    

    Pierwszy nie jest rozszerzalny, drugi jest zbyt ambitny, a trzeci jest naprawdę to, co masz na myśli, pisząc funkcje wirtualne.

  3. Kod dziedziczenia

    Kiedy piszesz kod, który opiera się na innej bibliotece, tak naprawdę nie wiesz, co może zrobić, gdy coś pójdzie nie tak.

    int lib_f();
    
    void g() throw( k_too_small_exception )
    { 
       int k = lib_f();
       if( k < 0 ) throw k_too_small_exception();
    }
    

    g kończy się, gdy lib_f() rzuca. To jest (w większości przypadków) nie to, czego naprawdę chcesz. std::terminate() nigdy nie powinien być wywoływany. Zawsze lepiej jest pozwolić aplikacji na awarię z nieobsługiwanym wyjątkiem, z ktorego mozna pobierac stos-Slad, niz cicho / brutalnie umierac.

  4. Napisz kod, który zwraca typowe błędy i rzuca przy wyjątkowych okazjach.

    Error e = open( "bla.txt" );
    if( e == FileNotFound )
        MessageUser( "File bla.txt not found" );
    if( e == AccessDenied )
        MessageUser( "Failed to open bla.txt, because we don't have read rights ..." );
    if( e != Success )
        MessageUser( "Failed due to some other error, error code = " + itoa( e ) );
    
    try
    {
       std::vector<TObj> k( 1000 );
       // ...
    }
    catch( const bad_alloc& b )
    { 
       MessageUser( "out of memory, exiting process" );
       throw;
    }
    

Niemniej jednak, gdy biblioteka po prostu rzuca własne wyjątki, możesz użyć specyfikacji WYJĄTKÓW, aby określić swój zamiar.

 88
Author: Christopher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-23 12:55:01

Unikaj specyfikacji WYJĄTKÓW w C++. Powody, które podajesz w swoim pytaniu, są całkiem dobrym początkiem dla "Dlaczego".

[[0]}Zobacz Herb Sutter "pragmatyczne spojrzenie na specyfikacje WYJĄTKÓW" .
 42
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-14 08:39:42

Myślę, że standardowo oprócz konwencji (dla C++)
Wyjątki były eksperymentem w standardzie C++, który w większości się nie powiódł.
Wyjątkiem jest to, że specyfik no throw jest przydatny, ale powinieneś również dodać odpowiedni blok try catch wewnętrznie, aby upewnić się, że kod pasuje do specyfika. Herb Sutter ma stronę na ten temat. Gotch 82

W dodatku myślę, że warto opisać Gwarancje WYJĄTKÓW.

To w zasadzie dokumentacja o tym, jak na stan obiektu wpływają wyjątki uciekające od metody na tym obiekcie. Niestety nie są one egzekwowane lub w inny sposób wymienione przez kompilator.
Boost and Exceptions

Gwarancje WYJĄTKÓW

Brak Gwarancji:

Nie ma gwarancji co do stanu obiektu po tym, jak wyjątek ucieka metodzie
W takich sytuacjach obiekt nie powinien być już używany.

Gwarancja Podstawowa:

In prawie we wszystkich sytuacjach powinna to być minimalna gwarancja, jaką zapewnia metoda.
Gwarantuje to, że stan obiektu jest dobrze zdefiniowany i nadal może być konsekwentnie używany.

Silna gwarancja: (aka gwarancja transakcyjna)

To gwarantuje, że metoda zakończy się pomyślnie
Albo wyjątek zostanie wyrzucony i stan obiektów nie ulegnie zmianie.

Brak Gwarancji Rzutu:

Metoda gwarantuje, że nie wyjątki są dozwolone, aby propagować się z metody.
Wszystkie destruktory powinny mieć taką gwarancję.
/ N. B. Jeśli wyjątek ucieka destruktorowi, podczas gdy wyjątek jest już propagowany
/ aplikacja zakończy

 14
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-25 10:18:56

Gcc będzie emitować ostrzeżenia, gdy naruszysz specyfikacje WYJĄTKÓW. To, co robię, to używanie makr do używania specyfikacji WYJĄTKÓW tylko w trybie "lint" kompilować wyraźnie do sprawdzania, aby upewnić się, że wyjątki zgadzają się z moją dokumentacją.

 8
Author: Jeremy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 03:26:36

Jedynym użytecznym specyfikatorem wyjątków jest " throw ()", jak w"doesn' t throw".

 7
Author: Harold Ekstrom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 20:29:26

Nie. Jeśli ich użyjesz i zostanie wyrzucony wyjątek, którego nie podałeś, albo za pomocą kodu, albo kodu wywołanego przez Twój kod, domyślnym zachowaniem jest natychmiastowe zakończenie programu.

Uważam również, że ich użycie zostało wycofane w bieżących projektach standardu C++0x.

 4
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 01:49:04

Specyfikacje WYJĄTKÓW nie są cudownie użytecznymi narzędziami w C++. Jednakże, istnieje/ jest / dobre zastosowanie dla nich, jeśli w połączeniu z std:: unexpected.

W niektórych projektach robię Kod ze specyfikacją wyjątków, a następnie wywołuję set_unexpected() z funkcją, która rzuci specjalny wyjątek mojego własnego projektu. Ten wyjątek, po zbudowaniu, otrzymuje backtrace (w sposób specyficzny dla platformy) i jest pochodną STD:: bad_exception (aby umożliwić jego rozpropagowanie w razie potrzeby). Jeśli to powoduje wywołanie terminate (), jak to zwykle robi, backtrace jest drukowane przez what () (jak również oryginalny wyjątek, który go spowodował; nie trudno go znaleźć), więc dostaję informacje o tym, gdzie moja umowa została naruszona, na przykład jaki nieoczekiwany wyjątek biblioteki został wyrzucony.

Jeśli to zrobię, nigdy nie zezwalam na rozmnażanie WYJĄTKÓW bibliotecznych (z wyjątkiem std) i wyprowadzam wszystkie moje wyjątki ze STD:: exception. Jeśli Biblioteka zdecyduje się rzucić, złapię i przekonwertuję na własną hierarchię, pozwalając mi zawsze kontrolować kod. Funkcje template, które wywołują funkcje zależne, powinny unikać specyfikacji WYJĄTKÓW z oczywistych powodów; ale rzadko zdarza się mieć interfejs funkcji template z kodem biblioteki (a kilka bibliotek naprawdę używa szablonów w użyteczny sposób).

 4
Author: coppro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-20 19:17:40

Jeśli piszesz kod, który będzie używany przez osoby, które wolą patrzeć na deklarację funkcji niż komentarze wokół niej, wtedy Specyfikacja powie im, które wyjątki mogą chcieć złapać.

W Przeciwnym Razie nie uważam za szczególnie przydatne używać czegokolwiek poza throw(), aby wskazać, że nie wyrzuca żadnych WYJĄTKÓW.

 3
Author: Branan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 23:13:54

Specyfikacja "throw()" pozwala kompilatorowi wykonać pewne optymalizacje podczas analizy przepływu kodu, jeśli wie, że funkcja nigdy nie wyrzuci wyjątku (lub przynajmniej obiecuje, że nigdy nie wyrzuci wyjątku). Larry Osterman opowiada o tym krótko tutaj:

Http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx

 3
Author: TheJuice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-01 15:13:31

Generalnie nie używałbym specyfików WYJĄTKÓW. Jednak w przypadkach, gdy jakikolwiek inny wyjątek miałby pochodzić z danej funkcji, której program ostatecznie nie byłby w stanie skorygować , może to być użyteczne. We wszystkich przypadkach należy wyraźnie udokumentować, jakich WYJĄTKÓW można oczekiwać od tej funkcji.

Tak, oczekiwanym zachowaniem niewyszczególnionego wyjątku wyrzucanego z funkcji ze specyfikatorami wyjątków jest wywołanie terminate ().

I zauważ również, że Scott Meyers porusza ten temat w bardziej efektywnym C++. Jego skuteczne C++ i bardziej efektywne C++ są bardzo polecane książki.

 2
Author: Kris Kumler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 23:12:59

Tak, jeśli jesteś w wewnętrznej dokumentacji. A może napisanie libary, z której inni będą korzystać, aby mogli powiedzieć, co się dzieje bez konsultacji z dokumentacją. Rzucanie lub nie rzucanie może być uważane za część API, prawie jak wartość zwracana.

Zgadzam się, nie są one naprawdę przydatne do wymuszania poprawności stylu Java w kompilatorze, ale to lepsze niż nic lub przypadkowe komentarze.

 2
Author: user10392,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 23:17:13

Mogą być użyteczne do testowania jednostkowego tak, że podczas pisania testów wiesz, czego oczekiwać od funkcji, która rzuci, gdy się nie powiedzie, ale nie ma otaczającego ich egzekwowania w kompilatorze. Myślę, że są to dodatkowe kody, które nie są konieczne w C++. Co zawsze wybrać wszystko, co powinieneś mieć pewność, to to, że postępujesz zgodnie z tym samym standardem kodowania w całym projekcie i członków zespołu, aby Twój kod pozostał czytelny.

 2
Author: Odd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 23:26:58

Z Artykułu:

Http://www.boost.org/community/exception_safety.html

" wiadomo, że niemożliwe jest napisz wyjątek - Bezpieczny generic Pojemnik."To twierdzenie jest często słyszane w nawiązaniu do artykułu Tomka Cargill [4], w którym bada problem WYJĄTKÓW-bezpieczeństwo dla ogólny szablon stosu. W jego artykuł, Cargill podnosi wiele przydatnych pytania, ale niestety nie przedstawić rozwiązanie jego problemu.1 on podsumowując, sugerując, że rozwiązanie może nie być możliwe. Niestety, jego artykuł został przeczytany przez wielu jako "dowód" tej spekulacji. Od czasu jej publikacji zostały wiele przykładów WYJĄTKÓW-bezpieczne komponenty generyczne, wśród nich C++ standardowe kontenery biblioteczne.

I rzeczywiście mogę myśleć o sposobach, aby wyjątek klas szablonów był bezpieczny. Jeśli nie masz kontroli nad wszystkimi podklasami, możesz mieć problem i tak. Aby to zrobić można stworzyć typedefs w klasach, które definiują wyjątki rzucane przez różne klasy szablonów. Myślę, że problem polega na tym, że jak zawsze wkładamy go później, a nie projektujemy go od początku i myślę, że to ten nad głową jest prawdziwą przeszkodą.

 0
Author: Marius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-21 17:11:39

Exception specifications = śmieci, zapytaj każdego programistę Java powyżej 30 roku życia

 -1
Author: Greg Dean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-20 19:22:28