Základní koncepce při práci se spravovanými výjimkami
Toto téma popisuje zpracování výjimek ve spravovaných aplikacích. To znamená, že aplikace kompilovaná s možností kompilátoru /clr .
V tomto tématu
Poznámky
Pokud kompilujete pomocí možnosti /clr , můžete zpracovat výjimky CLR i standardní Exception třídu poskytuje mnoho užitečných metod pro zpracování výjimek CLR a doporučuje se jako základní třída pro třídy výjimek definovaných uživatelem.
Zachytávání typů výjimek odvozených z rozhraní není podporováno v / clr. Modul CLR (Common Language Runtime) také neumožňuje zachytit výjimky přetečení zásobníku; Výjimka přetečení zásobníku ukončí proces.
Další informace o rozdílech v zpracování výjimek ve spravovaných a nespravovaných aplikacích najdete v tématu Rozdíly v chování zpracování výjimek v části Spravovaná rozšíření jazyka C++.
Vyvolání výjimek v /clr
Výraz vyvolání jazyka C++ je rozšířen o vyvolání popisovače na typ CLR. Následující příklad vytvoří vlastní typ výjimky a pak vyvolá instanci tohoto typu:
// clr_exception_handling.cpp
// compile with: /clr /c
ref struct MyStruct: public System::Exception {
public:
int i;
};
void GlobalFunction() {
MyStruct^ pMyStruct = gcnew MyStruct;
throw pMyStruct;
}
Před vyvoláním musí být typ hodnoty v rámečku:
// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
int i;
};
void GlobalFunction() {
MyValueStruct v = {11};
throw (MyValueStruct ^)v;
}
Try/Catch Blocks for CLR Extensions
Stejnou try
/catch
strukturu bloku lze použít k zachycení clr i nativních výjimek:
// clr_exception_handling_3.cpp
// compile with: /clr
using namespace System;
ref struct MyStruct : public Exception {
public:
int i;
};
struct CMyClass {
public:
double d;
};
void GlobalFunction() {
MyStruct^ pMyStruct = gcnew MyStruct;
pMyStruct->i = 11;
throw pMyStruct;
}
void GlobalFunction2() {
CMyClass c = {2.0};
throw c;
}
int main() {
for ( int i = 1; i >= 0; --i ) {
try {
if ( i == 1 )
GlobalFunction2();
if ( i == 0 )
GlobalFunction();
}
catch ( CMyClass& catchC ) {
Console::WriteLine( "In 'catch(CMyClass& catchC)'" );
Console::WriteLine( catchC.d );
}
catch ( MyStruct^ catchException ) {
Console::WriteLine( "In 'catch(MyStruct^ catchException)'" );
Console::WriteLine( catchException->i );
}
}
}
Výstup
In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11
Pořadí odvíjení pro objekty C++
Uvolnění probíhá u všech objektů C++ s destruktory, které mohou být v zásobníku za běhu mezi vyvolání funkce a funkcí zpracování. Vzhledem k tomu, že typy CLR jsou přiděleny na haldě, unwinding se na ně nevztahuje.
Pořadí událostí pro vyvolánou výjimku je následující:
Modul runtime provede zásobník vyhledáním příslušné klauzule catch nebo v případě SEH, s výjimkou filtru pro SEH, aby se výjimka zachytila. Klauzule Catch se prohledávají jako první v lexikálním pořadí a pak dynamicky dolů zásobník volání.
Jakmile se najde správná obslužná rutina, zásobník se v tomto bodě rozbalí. Pro každé volání funkce v zásobníku jsou jeho místní objekty destrukovány a __finally bloky se spouští, od většiny vnořených směrem ven.
Jakmile je zásobník unwound, spustí se klauzule catch.
Zachycení nespravovaných typů
Pokud je vyvolán nespravovaný typ objektu, je zabalen s výjimkou typu SEHException. Při hledání příslušné catch
klauzule existují dvě možnosti.
Pokud je zjištěn nativní typ jazyka C++, výjimka se rozbalí a porovná se s typem, který byl zjištěn. Toto porovnání umožňuje zachytit nativní typ jazyka C++ normálním způsobem.
Pokud
catch
je však nejprve zkoumána klauzule typu SEHException nebo některé z jejích základních tříd, klauzule zachytí výjimku. Proto byste měli nejprve umístit všechny klauzule catch, které zachytí nativní typy C++, před všechny klauzule catch typů CLR.
Všimněte si, že
catch(Object^)
a
catch(...)
zachytí všechny vyvolané typy včetně výjimek SEH.
Pokud je nespravovaný typ zachycen catch(Object^), nezničí vyvolaný objekt.
Při vyvolání nebo zachytávání nespravovaných výjimek doporučujeme místo /EHs nebo /EHa použít možnost kompilátoru /EHsc.