Bagikan melalui


Menangani pengecualian terstruktur di C++

Perbedaan utama antara penanganan pengecualian terstruktur C (SEH) dan penanganan pengecualian C++ adalah bahwa model penanganan pengecualian C++ menangani jenis, sementara model penanganan pengecualian terstruktur C berkaitan dengan pengecualian satu jenis; khususnya, unsigned int. Artinya, pengecualian C diidentifikasi oleh nilai bilangan bulat yang tidak ditandatangani, sedangkan pengecualian C++ diidentifikasi berdasarkan jenis data. Ketika pengecualian terstruktur dimunculkan di C, setiap handler yang mungkin menjalankan filter yang memeriksa konteks pengecualian C dan menentukan apakah akan menerima pengecualian, meneruskannya ke beberapa handler lain, atau mengabaikannya. Ketika pengecualian dilemparkan dalam C++, mungkin dari jenis apa pun.

Perbedaan kedua adalah bahwa model penanganan pengecualian terstruktur C disebut sebagai asinkron, karena pengecualian terjadi sekunder pada alur kontrol normal. Mekanisme penanganan pengecualian C++ sepenuhnya sinkron, yang berarti bahwa pengecualian hanya terjadi ketika dilemparkan.

Saat Anda menggunakan opsi pengkompilasi /EHsc atau /EHsc , tidak ada handler pengecualian C++ yang menangani pengecualian terstruktur. Pengecualian ini hanya ditangani oleh __except penangan pengecualian terstruktur atau __finally penangan penghentian terstruktur. Untuk informasi, lihat Penanganan Pengecualian Terstruktur (C/C++).

Di bawah opsi pengkompilasi /EHa, jika pengecualian C dinaikkan dalam program C++, itu dapat ditangani oleh handler pengecualian terstruktur dengan filter terkait atau oleh handler C++catch, mana yang secara dinamis lebih dekat dengan konteks pengecualian. Misalnya, contoh program C++ ini memunculkan pengecualian C di dalam konteks C++ try :

Contoh - Menangkap pengecualian C di blok tangkapan C++

// exceptions_Exception_Handling_Differences.cpp
// compile with: /EHa
#include <iostream>

using namespace std;
void SEHFunc( void );

int main() {
   try {
      SEHFunc();
   }
   catch( ... ) {
      cout << "Caught a C exception."<< endl;
   }
}

void SEHFunc() {
   __try {
      int x, y = 0;
      x = 5 / y;
   }
   __finally {
      cout << "In finally." << endl;
   }
}
In finally.
Caught a C exception.

Kelas pembungkus pengecualian C

Dalam contoh sederhana seperti di atas, pengecualian C hanya dapat ditangkap oleh handler elipsis (...). catch Tidak ada informasi tentang jenis atau sifat pengecualian yang dikomunikasikan ke handler. Meskipun metode ini berfungsi, dalam beberapa kasus Anda mungkin ingin menentukan transformasi antara dua model penanganan pengecualian sehingga setiap pengecualian C dikaitkan dengan kelas tertentu. Untuk mengubahnya, Anda dapat menentukan kelas "pembungkus" pengecualian C, yang dapat digunakan atau berasal dari untuk mengaitkan jenis kelas tertentu ke pengecualian C. Dengan demikian, setiap pengecualian C dapat ditangani secara terpisah oleh handler C++ catch tertentu, alih-alih semuanya dalam satu handler.

Kelas pembungkus Anda mungkin memiliki antarmuka yang terdiri dari beberapa fungsi anggota yang menentukan nilai pengecualian, dan yang mengakses informasi konteks pengecualian yang diperluas yang disediakan oleh model pengecualian C. Anda mungkin juga ingin menentukan konstruktor default dan konstruktor yang menerima argumen (untuk menyediakan representasi pengecualian C yang mendasar unsigned int ), dan konstruktor salinan bitwise. Berikut adalah kemungkinan implementasi kelas pembungkus pengecualian C:

// exceptions_Exception_Handling_Differences2.cpp
// compile with: /c
class SE_Exception {
private:
   SE_Exception() {}
   SE_Exception( SE_Exception& ) {}
   unsigned int nSE;
public:
   SE_Exception( unsigned int n ) : nSE( n ) {}
   ~SE_Exception() {}
   unsigned int getSeNumber() {
      return nSE;
   }
};

Untuk menggunakan kelas ini, instal fungsi terjemahan pengecualian C kustom yang dipanggil oleh mekanisme penanganan pengecualian internal setiap kali pengecualian C dilemparkan. Dalam fungsi terjemahan Anda, Anda dapat melemparkan pengecualian yang diketik (mungkin SE_Exception jenis, atau jenis kelas yang berasal dari SE_Exception) yang dapat ditangkap oleh handler C++ catch yang sesuai. Fungsi terjemahan dapat kembali, yang menunjukkan bahwa fungsi tersebut tidak menangani pengecualian. Jika fungsi terjemahan itu sendiri menimbulkan pengecualian C, hentikan dipanggil.

Untuk menentukan fungsi terjemahan kustom, panggil fungsi _set_se_translator dengan nama fungsi terjemahan Anda sebagai argumen tunggalnya. Fungsi terjemahan yang Anda tulis dipanggil sekali untuk setiap pemanggilan fungsi pada tumpukan yang memiliki try blok. Tidak ada fungsi terjemahan default; jika Anda tidak menentukannya dengan memanggil _set_se_translator, pengecualian C hanya dapat ditangkap oleh handler elipsis catch .

Contoh - Menggunakan fungsi terjemahan kustom

Misalnya, kode berikut menginstal fungsi terjemahan kustom, lalu menaikkan pengecualian C yang dibungkus oleh SE_Exception kelas :

// exceptions_Exception_Handling_Differences3.cpp
// compile with: /EHa
#include <stdio.h>
#include <eh.h>
#include <windows.h>

class SE_Exception {
private:
   SE_Exception() {}
   unsigned int nSE;
public:
   SE_Exception( SE_Exception& e) : nSE(e.nSE) {}
   SE_Exception(unsigned int n) : nSE(n) {}
   ~SE_Exception() {}
   unsigned int getSeNumber() { return nSE; }
};

void SEFunc() {
    __try {
        int x, y = 0;
        x = 5 / y;
    }
    __finally {
        printf_s( "In finally\n" );
    }
}

void trans_func( unsigned int u, _EXCEPTION_POINTERS* pExp ) {
    printf_s( "In trans_func.\n" );
    throw SE_Exception( u );
}

int main() {
    _set_se_translator( trans_func );
    try {
        SEFunc();
    }
    catch( SE_Exception e ) {
        printf_s( "Caught a __try exception with SE_Exception.\n" );
        printf_s( "nSE = 0x%x\n", e.getSeNumber() );
    }
}
In trans_func.
In finally
Caught a __try exception with SE_Exception.
nSE = 0xc0000094

Baca juga

Pengecualian Mixing C (Terstruktur) dan C++