Funksional try bloki. Ko'p hollarda try va catch bloklarining funksionalligi yetarli, ammo ularning standart funksionalligi yetishmayotgan bitta aniq vaziyat mavjud. Quyidagi kodni ko'rib chiqamiz:
#include
class A
{
private:
int m_x;
public:
A(int x) : m_x(x)
{
if (x <= 0)
throw 1;
}
};
class B : public A
{
public:
B(int x) : A(x)
{
// Agar A bajarilmasa va istisno bu yerda ko'rib chiqilishi kerak bo'lsa nima bo'ladi?
}
};
int main()
{
try
{
B b(0);
}
catch (int)
{
std::cout << "Oops!\n";
}
}
Yuqoridagi dasturda B sinfining avlodi A sinfining konstruktorini chaqiradi, bu esa istisno qiladi (agar shart muvaffaqiyatli bo'lsa). B obyekti main () ning try blokida yaratilganligi sababli, agar A istisno qilsa, main() ning try bloki uni ushlaydi va catch (int) ishlov beruvchisiga uzatadi.
Shunday qilib, dasturni bajarish natijasi:
Oops!
Ammo B sinfidagi istisnolarni hal qilishimiz kerak bo'lsa-chi? A sinfining konstruktoriga murojaat a'zolarni ishga tushirish ro'yxati orqali, B sinfi konstruktorining tanasini bajarishdan oldin sodir bo'ladi. Shuning uchun bu erda standart try blokidan foydalanish ishlamaydi.
Bunday holda, biz biroz o'zgartirilgan try blokidan foydalanishimiz kerak - funksional try bloki. Funksional sinash bloki istisno ishlovchini funksiyaning faqat ma'lum bir qismi (kod bloki) atrofida emas, balki butun tanasi atrofida joylashtirish uchun ishlatiladi.
Sintaksisni tasvirlash biroz murakkab, shuning uchun keling, hamma narsani misol bilan ko'rib chiqaylik:
#include
class A
{
private:
int m_x;
public:
A(int x) : m_x(x)
{
if (x <= 0)
throw 1;
}
};
class B : public A
{
public:
B(int x) try : A(x) // bu yerda try kalit so'ziga e'tibor bering
{
}
catch (...) // bu blok konstruktor bilan bir xil chekinish darajasida ekanligini unutmang
{
// B sinf a'zolarining ishga tushirish ro'yxatidan yoki
//konstruktor tanasidan istisnolar bu yerda ko'rib chiqiladi
cerr << "Construction of A failed\n";
// Agar biz bu erda aniq istisno qilmasak,
//joriy (ushlangan) istisno qayta tashlanadi va murojaatlar to'plamiga suriladi.
}
};
int main()
{
try
{
B b(0);
}
catch (int)
{
std::cout << "Oops!\n";
}
}
Dasturni bajarish natijasi:
Konstruktor muvaffaqiyatsiz tugadi
OOps!
Keling, ushbu dasturni batafsil ko'rib chiqaylik.
Birinchidan, B sinfidagi a'zolarni ishga tushirish ro'yxatidan oldin try kalit so'zining qo'shilganiga e'tibor bering. Bu shuni anglatadiki, bu kalit so'zdan keyingi hamma narsa (funktsiyaning oxirigacha) try blokining bir qismi hisoblanadi.
Ikkinchidan, catch bloki butun funksiya bilan bir xil chekinish darajasida. try kalit so'zi va konstruktor tanasining oxiri o'rtasida tashlangan har qanday istisno bir xil catch bloki tomonidan qayta ishlanadi.
Nihoyat, istisnolarni ko'rib chiqadigan, yangi istisnolarni chiqaradigan yoki tutilgan istisnoni qayta tiklaydigan oddiy catch bloklaridan farqli o'laroq, funksiyani sinab ko'rish bloklaridan foydalanganda siz yangi istisnoni tashlashingiz yoki ushlangan istisnoni qaytadan tashlashingiz kerak. Agar shunday qilmasangiz, ushlangan istisno qayta tashlanadi va stek yechila boshlaydi.
Yuqoridagi dasturda biz catch bloki ichida istisnoni aniq tashlamaganimiz sababli, istisno qayta tashlanadi va qo'ng'iroq qiluvchiga bir daraja yuqoriga uzatiladi, ya'ni. asosiy () funktsiyasiga. Asosiy () funktsiyasining catch bloki istisnoni ushlaydi va boshqaradi va biz afsuski!
Funktsional try bloklari sinf usullari bo'lmagan muntazam funktsiyalar bilan ham qo'llanilishi mumkin bo'lsa-da, bu odatiy amaliyot emas, chunki ular foydali bo'lishi mumkin bo'lgan juda kam holatlar mavjud. Ular deyarli har doim faqat konstruktorlar bilan ishlatiladi!
Do'stlaringiz bilan baham: |