Sdílet prostřednictvím


Specifikace výjimek (throw, noexcept) (C++)

Specifikace výjimek jsou funkce jazyka C++, která označuje záměr programátora o typech výjimek, které lze rozšířit funkcí. Můžete určit, že funkce může nebo nemusí ukončit výjimku pomocí specifikace výjimky. Kompilátor může tyto informace použít k optimalizaci volání funkce a k ukončení programu, pokud neočekávaná výjimka unikne funkci.

Před C++17 byly dva druhy specifikace výjimek. Specifikace noexcept byla v jazyce C++11 nová. Určuje, jestli je sada potenciálních výjimek, které mohou utéct funkci, prázdná. Specifikace dynamické výjimky nebo throw(optional_type_list) specifikace byla v jazyce C++11 zastaralá a odebrána v jazyce C++17 s výjimkou throw(), což je alias pro noexcept(true). Tato specifikace výjimky byla navržena tak, aby poskytovala souhrnné informace o výjimkách, které mohou být vyvolány z funkce, ale v praxi bylo zjištěno, že jsou problematické. Jednou dynamickou specifikací výjimek, která prokázala, že je poněkud užitečná, byla nepodmíněná throw() specifikace. Například deklarace funkce:

void MyFunction(int i) throw();

říká kompilátoru, že funkce nevyvolá žádné výjimky. V /std:c++14 režimu to ale může vést k nedefinovanýmu chování, pokud funkce vyvolá výjimku. Proto doporučujeme místo výše uvedeného operátoru noexcept použít:

void MyFunction(int i) noexcept;

Následující tabulka shrnuje implementaci specifikace výjimek v jazyce Microsoft C++:

Specifikace výjimek Význam
noexcept
noexcept(true)
throw()
Funkce nevyvolá výjimku. V /std:c++14 režimu (což je výchozí) noexcept a noexcept(true) jsou ekvivalentní. Pokud je vyvolána výjimka z funkce, která je deklarována noexcept nebo noexcept(true), std::terminate je vyvolána. Pokud je vyvolána výjimka z funkce deklarované jako throw() v /std:c++14 režimu, výsledek je nedefinované chování. Není vyvolána žádná konkrétní funkce. Jedná se o rozdíly od standardu C++14, který vyžadoval vyvolání std::unexpectedkompilátoru .
Visual Studio 2017 verze 15.5 a novější: V /std:c++17 režimu , noexcept, noexcept(true)a throw() jsou všechny ekvivalentní. V /std:c++17 režimu throw() je alias pro noexcept(true). Pokud je v /std:c++17 režimu a později vyvolána výjimka z funkce deklarované s některou z těchto specifikací, std::terminate je vyvolána podle požadavků standardu C++17.
noexcept(false)
throw(...)
Bez specifikace
Funkce může vyvolat výjimku jakéhokoli typu.
throw(type) (C++14 a starší) Funkce může vyvolat výjimku typu type. Kompilátor přijímá syntaxi, ale interpretuje ji jako noexcept(false). V /std:c++17 režimu a novějším kompilátoru zobrazí upozornění C5040.

Pokud se v aplikaci používá zpracování výjimek, musí být v zásobníku volání funkce, která zpracovává vyvolané výjimky před ukončením vnějšího rozsahu označené noexceptfunkce , noexcept(true)nebo throw(). Pokud jsou některé funkce volané mezi funkcemi, které vyvolá výjimku, a funkce, která zpracovává výjimku, zadány jako noexcept, noexcept(true) (nebo throw() v /std:c++17 režimu), program se ukončí, když funkce noexcept rozšíří výjimku.

Chování výjimky funkce závisí na následujících faktorech:

  • Který standardní režim kompilace jazyka je nastavený.

  • Bez ohledu na to, jestli kompilujete funkci v jazyce C nebo C++.

  • Kterou /EH možnost kompilátoru použijete.

  • Bez ohledu na to, jestli explicitně zadáte specifikaci výjimky.

Explicitní specifikace výjimek nejsou u funkcí jazyka C povoleny. Funkce jazyka C se předpokládá, že nevyvolá výjimky v rámci /EHsc, a může vyvolat strukturované výjimky v /EHsoblasti , /EHanebo /EHac.

Následující tabulka shrnuje, jestli může funkce jazyka C++ potenciálně vyvolat různé možnosti zpracování výjimek kompilátoru:

Function /EHsc /EHs /EHa /EHac
Funkce C++ bez specifikace výjimek Ano Ano Ano Ano
Funkce jazyka C++ se noexceptspecifikací , noexcept(true)nebo throw() výjimky Číslo No Ano Ano
Funkce jazyka C++ se noexcept(false)specifikací , throw(...)nebo throw(type) výjimky Ano Ano Ano Ano

Příklad

// exception_specification.cpp
// compile with: /EHs
#include <stdio.h>

void handler() {
   printf_s("in handler\n");
}

void f1(void) throw(int) {
   printf_s("About to throw 1\n");
   if (1)
      throw 1;
}

void f5(void) throw() {
   try {
      f1();
   }
   catch(...) {
      handler();
    }
}

// invalid, doesn't handle the int exception thrown from f1()
// void f3(void) throw() {
//   f1();
// }

void __declspec(nothrow) f2(void) {
   try {
      f1();
   }
   catch(int) {
      handler();
    }
}

// only valid if compiled without /EHc
// /EHc means assume extern "C" functions don't throw exceptions
extern "C" void f4(void);
void f4(void) {
   f1();
}

int main() {
   f2();

   try {
      f4();
   }
   catch(...) {
      printf_s("Caught exception from f4\n");
   }
   f5();
}
About to throw 1
in handler
About to throw 1
Caught exception from f4
About to throw 1
in handler

Viz také

try, throwa catch příkazy (C++)
Moderní osvědčené postupy jazyka C++ pro výjimky a zpracování chyb