Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Dalam mekanisme pengecualian C++, kontrol berpindah dari pernyataan lemparan ke pernyataan tangkapan pertama yang dapat menangani jenis yang dilemparkan. Ketika pernyataan tangkapan tercapai, semua variabel otomatis yang berada dalam cakupan antara pernyataan lemparan dan tangkapan dihancurkan dalam proses yang dikenal sebagai stack unwinding. Dalam unwinding tumpukan, eksekusi berlanjut sebagai berikut:
Kontrol mencapai
trypernyataan berdasarkan eksekusi berurutan normal. Bagian yang dijaga ditryblok dijalankan.Jika tidak ada pengecualian yang dilemparkan selama eksekusi bagian yang dijaga,
catchklausul yang mengikutitryblok tidak dijalankan. Eksekusi berlanjut pada pernyataan setelah klausul terakhircatchyang mengikuti blok terkaittry.Jika pengecualian dilemparkan selama eksekusi bagian yang dijaga atau dalam rutinitas apa pun yang dipanggil bagian yang dijaga baik secara langsung atau tidak langsung, objek pengecualian dibuat dari objek yang dibuat oleh
throwoperand. (Ini menyiratkan bahwa konstruktor salinan mungkin terlibat.) Pada titik ini, pengkompilasi mencaricatchklausul dalam konteks eksekusi yang lebih tinggi yang dapat menangani pengecualian jenis yang dilemparkan, atau untukcatchhandler yang dapat menangani semua jenis pengecualian. Handlercatchdiperiksa dalam urutan penampilan mereka setelahtryblok. Jika tidak ada handler yang sesuai yang ditemukan, blok penutup dinamistryberikutnya akan diperiksa. Proses ini berlanjut sampai blok penutup terluartrydiperiksa.Jika handler yang cocok masih belum ditemukan, atau jika terjadi pengecualian selama proses unwinding tetapi sebelum handler mendapatkan kontrol, fungsi
terminaterun-time yang telah ditentukan sebelumnya dipanggil. Jika pengecualian terjadi setelah pengecualian dilemparkan tetapi sebelum unwind dimulai,terminatedipanggil.Jika handler yang
catchcocok ditemukan, dan menangkap berdasarkan nilai, parameter formalnya diinisialisasi dengan menyalin objek pengecualian. Jika menangkap berdasarkan referensi, parameter diinisialisasi untuk merujuk ke objek pengecualian. Setelah parameter formal diinisialisasi, proses melepas tumpukan dimulai. Ini melibatkan penghancuran semua objek otomatis yang sepenuhnya dibangun—tetapi belum dihancurkan—antara awaltryblok yang terkait dengancatchhandler dan situs lemparan pengecualian. Penghancuran terjadi dalam urutan terbalik konstruksi. Handlercatchdijalankan dan program melanjutkan eksekusi setelah handler terakhir—yaitu, pada pernyataan pertama atau konstruksi yang bukan handlercatch. Kontrol hanya dapat memasukkancatchhandler melalui pengecualian yang dilemparkan, tidak pernah melaluigotopernyataan ataucaselabel dalamswitchpernyataan.
Contoh unwinding tumpukan
Contoh berikut menunjukkan bagaimana tumpukan dilepas saat pengecualian dilemparkan. Eksekusi pada utas melompat dari pernyataan C lemparan ke pernyataan tangkapan di main, dan melepas lelah setiap fungsi di sepanjang jalan. Perhatikan urutan Dummy pembuatan objek dan kemudian dihancurkan saat keluar dari cakupan. Perhatikan juga bahwa tidak ada fungsi yang selesai kecuali main, yang berisi pernyataan tangkapan. Fungsi A tidak pernah kembali dari panggilannya ke B(), dan B tidak pernah kembali dari panggilannya ke C(). Jika Anda membatalkan komentar definisi Dummy pointer dan pernyataan penghapusan yang sesuai, lalu menjalankan program, perhatikan bahwa pointer tidak pernah dihapus. Ini menunjukkan apa yang dapat terjadi ketika fungsi tidak memberikan jaminan pengecualian. Untuk informasi selengkapnya, lihat Cara: Desain untuk Pengecualian. Jika Anda mengomentari pernyataan tangkapan, Anda dapat mengamati apa yang terjadi ketika program berakhir karena pengecualian yang tidak tertangani.
#include <string>
#include <iostream>
using namespace std;
class MyException{};
class Dummy
{
public:
Dummy(string s) : MyName(s) { PrintMsg("Created Dummy:"); }
Dummy(const Dummy& other) : MyName(other.MyName){ PrintMsg("Copy created Dummy:"); }
~Dummy(){ PrintMsg("Destroyed Dummy:"); }
void PrintMsg(string s) { cout << s << MyName << endl; }
string MyName;
int level;
};
void C(Dummy d, int i)
{
cout << "Entering FunctionC" << endl;
d.MyName = " C";
throw MyException();
cout << "Exiting FunctionC" << endl;
}
void B(Dummy d, int i)
{
cout << "Entering FunctionB" << endl;
d.MyName = "B";
C(d, i + 1);
cout << "Exiting FunctionB" << endl;
}
void A(Dummy d, int i)
{
cout << "Entering FunctionA" << endl;
d.MyName = " A" ;
// Dummy* pd = new Dummy("new Dummy"); //Not exception safe!!!
B(d, i + 1);
// delete pd;
cout << "Exiting FunctionA" << endl;
}
int main()
{
cout << "Entering main" << endl;
try
{
Dummy d(" M");
A(d,1);
}
catch (MyException& e)
{
cout << "Caught an exception of type: " << typeid(e).name() << endl;
}
cout << "Exiting main." << endl;
char c;
cin >> c;
}
/* Output:
Entering main
Created Dummy: M
Copy created Dummy: M
Entering FunctionA
Copy created Dummy: A
Entering FunctionB
Copy created Dummy: B
Entering FunctionC
Destroyed Dummy: C
Destroyed Dummy: B
Destroyed Dummy: A
Destroyed Dummy: M
Caught an exception of type: class MyException
Exiting main.
*/