Bagikan melalui


Perbedaan Perilaku Penanganan Pengecualian Di bawah /CLR

Konsep Dasar dalam Menggunakan Pengecualian Terkelola membahas penanganan pengecualian dalam aplikasi terkelola. Dalam topik ini, perbedaan dari perilaku standar penanganan pengecualian dan beberapa pembatasan dibahas secara rinci. Untuk informasi selengkapnya, lihat Fungsi _set_se_translator.

Melompat Keluar dari Blok Akhirnya

Dalam kode C/C++ asli, melompat keluar dari blok __finally menggunakan penanganan pengecualian terstruktur (SEH) diizinkan meskipun menghasilkan peringatan. Di bawah /clr, melompat keluar dari blok akhirnya menyebabkan kesalahan:

// clr_exception_handling_4.cpp
// compile with: /clr
int main() {
   try {}
   finally {
      return 0;   // also fails with goto, break, continue
    }
}   // C3276

Meningkatkan Pengecualian Dalam Filter Pengecualian

Ketika pengecualian dinaikkan selama pemrosesan filter pengecualian dalam kode terkelola, pengecualian ditangkap dan diperlakukan seolah-olah filter mengembalikan 0.

Ini berbeda dengan perilaku dalam kode asli di mana pengecualian berlapis dinaikkan, bidang ExceptionRecord di struktur EXCEPTION_RECORD (seperti yang dikembalikan oleh GetExceptionInformation) diatur, dan bidang ExceptionFlags mengatur bit 0x10. Contoh berikut mengilustrasikan perbedaan perilaku ini:

// clr_exception_handling_5.cpp
#include <windows.h>
#include <stdio.h>
#include <assert.h>

#ifndef false
#define false 0
#endif

int *p;

int filter(PEXCEPTION_POINTERS ExceptionPointers) {
   PEXCEPTION_RECORD ExceptionRecord =
                     ExceptionPointers->ExceptionRecord;

   if ((ExceptionRecord->ExceptionFlags & 0x10) == 0) {
      // not a nested exception, throw one
      *p = 0; // throw another AV
   }
   else {
      printf("Caught a nested exception\n");
      return 1;
    }

   assert(false);

   return 0;
}

void f(void) {
   __try {
      *p = 0;   // throw an AV
   }
   __except(filter(GetExceptionInformation())) {
      printf_s("We should execute this handler if "
                 "compiled to native\n");
    }
}

int main() {
   __try {
      f();
   }
   __except(1) {
      printf_s("The handler in main caught the "
               "exception\n");
    }
}

Output

Caught a nested exception
We should execute this handler if compiled to native

Disasosiasi Rethrows

/clr tidak mendukung pencabutan pengecualian di luar handler tangkapan (dikenal sebagai rethrow yang disasosiasi). Pengecualian jenis ini diperlakukan sebagai rethrow C++ standar. Jika rethrow yang disasosiasi ditemui ketika ada pengecualian terkelola aktif, pengecualian dibungkus sebagai pengecualian C++ dan kemudian ditumbuhi kembali. Pengecualian jenis ini hanya dapat ditangkap sebagai pengecualian dari jenis SEHException.

Contoh berikut menunjukkan pengecualian terkelola yang ditumbuhi kembali sebagai pengecualian C++:

// clr_exception_handling_6.cpp
// compile with: /clr
using namespace System;
#include <assert.h>
#include <stdio.h>

void rethrow( void ) {
   // This rethrow is a dissasociated rethrow.
   // The exception would be masked as SEHException.
   throw;
}

int main() {
   try {
      try {
         throw gcnew ApplicationException;
      }
      catch ( ApplicationException^ ) {
         rethrow();
         // If the call to rethrow() is replaced with
         // a throw statement within the catch handler,
         // the rethrow would be a managed rethrow and
         // the exception type would remain
         // System::ApplicationException
      }
   }

    catch ( ApplicationException^ ) {
      assert( false );

      // This will not be executed since the exception
      // will be masked as SEHException.
    }
   catch ( Runtime::InteropServices::SEHException^ ) {
      printf_s("caught an SEH Exception\n" );
    }
}

Output

caught an SEH Exception

Filter pengecualian dan EXCEPTION_CONTINUE_EXECUTION

Jika filter kembali EXCEPTION_CONTINUE_EXECUTION dalam aplikasi terkelola, filter akan diperlakukan seolah-olah filter mengembalikan EXCEPTION_CONTINUE_SEARCH. Untuk informasi selengkapnya tentang konstanta ini, lihat Pernyataan try-except.

Contoh berikut menunjukkan perbedaan ini:

// clr_exception_handling_7.cpp
#include <windows.h>
#include <stdio.h>
#include <assert.h>

int main() {
   int Counter = 0;
   __try {
      __try  {
         Counter -= 1;
         RaiseException (0xe0000000|'seh',
                         0, 0, 0);
         Counter -= 2;
      }
      __except (Counter) {
         // Counter is negative,
         // indicating "CONTINUE EXECUTE"
         Counter -= 1;
      }
    }
    __except(1) {
      Counter -= 100;
   }

   printf_s("Counter=%d\n", Counter);
}

Output

Counter=-3

Fungsi _set_se_translator

Fungsi penerjemah, diatur oleh panggilan ke _set_se_translator, hanya memengaruhi tangkapan dalam kode yang tidak dikelola. Contoh berikut menunjukkan batasan ini:

// clr_exception_handling_8.cpp
// compile with: /clr /EHa
#include <iostream>
#include <windows.h>
#include <eh.h>
#pragma warning (disable: 4101)
using namespace std;
using namespace System;

#define MYEXCEPTION_CODE 0xe0000101

class CMyException {
public:
   unsigned int m_ErrorCode;
   EXCEPTION_POINTERS * m_pExp;

   CMyException() : m_ErrorCode( 0 ), m_pExp( NULL ) {}

   CMyException( unsigned int i, EXCEPTION_POINTERS * pExp )
         : m_ErrorCode( i ), m_pExp( pExp ) {}

   CMyException( CMyException& c ) : m_ErrorCode( c.m_ErrorCode ),
                                      m_pExp( c.m_pExp ) {}

   friend ostream& operator <<
                 ( ostream& out, const CMyException& inst ) {
      return out <<  "CMyException[\n" <<
             "Error Code: " << inst.m_ErrorCode <<  "]";
    }
};

#pragma unmanaged
void my_trans_func( unsigned int u, PEXCEPTION_POINTERS pExp ) {
   cout <<  "In my_trans_func.\n";
   throw CMyException( u, pExp );
}

#pragma managed
void managed_func() {
   try  {
      RaiseException( MYEXCEPTION_CODE, 0, 0, 0 );
   }
   catch ( CMyException x ) {}
   catch ( ... ) {
      printf_s("This is invoked since "
               "_set_se_translator is not "
               "supported when /clr is used\n" );
    }
}

#pragma unmanaged
void unmanaged_func() {
   try  {
      RaiseException( MYEXCEPTION_CODE,
                      0, 0, 0 );
   }
   catch ( CMyException x ) {
      printf("Caught an SEH exception with "
             "exception code: %x\n", x.m_ErrorCode );
    }
    catch ( ... ) {}
}

// #pragma managed
int main( int argc, char ** argv ) {
   _set_se_translator( my_trans_func );

   // It does not matter whether the translator function
   // is registered in managed or unmanaged code
   managed_func();
   unmanaged_func();
}

Output

This is invoked since _set_se_translator is not supported when /clr is used
In my_trans_func.
Caught an SEH exception with exception code: e0000101

Lihat juga

Penanganan Pengecualian
safe_cast
Penanganan Pengecualian di MSVC