در این جلسه به بررسی مدیریت استثناها در ++C یا Exception Handling میپردازیم. یک استثنا حالتی غیرطبیعی است که ممکن است در حین اجرای یک برنامه رخ دهد. یک استثنا در ++C پاسخی است که برای یک وضعیت ویژه پیش آمده حین اجرای برنامه ، مانند تقسیم بر صفر، تدارک دیده شده است.
استثناها راهی برای انتقال کنترل برنامه از یک بخش به بخش دیگر برنامه فراهم میکنند. استثنا در ++C با سه کلید واژه ساخته میشود: try ،catch و throw.
- Thorw: یک برنامه هنگام رخ دادن مشکل، یک استثنا پرتاب (throw) میکند. این کار با استفاده از کلید واژه throw انجام میشود.
- Catch: در جایی که قرار است مشکل پیش آمده مدیریت شود، با استفاده از یک کنترل کننده استثنا (exception handler)، یک استثنا گرفته میشود.
- Try: بلوک try بلوک کدی، که ممکن است استثنای مشخصی در آن رخ دهد را شناسایی میکند. به دنبال این بلوک یک یا چند بلوک catch میآید.
فرض کنیم در یک بلوک یک استثنا رخ دهد، یک متد با استفاده از ترکیب کلید واژههای try و catch آن استثنا را میگیرد. بلوک try/catch حوالی کدی قرار میگیرد که احتمال دارد استثنا در آن رخ دهد. کد درون بلوک try/catch، کد محافظت شده نامیده میشود. ساختار استفاده از try/catch به صورت زیر است.
try { // protected code } catch( ExceptionName e1 ) { // catch block } catch( ExceptionName e2 ) { // catch block } catch( ExceptionName eN ) { // catch block }
میتوان لیستی از دستورات catch را برای گرفتن استثناهای مختلفی که ممکن است در بلوک try رخ دهد فراهم کرد، زیرا بسته به شرایط مختلف، ممکن است در یک بلوک try استثناهای مختلفی رخ دهد.
پرتاب کردن استثنا یا Throwing Exceptions
با استفاده از دستور throw میتوان استثناها را به هر جایی از بلوک پرتاب کرد. عملوند دستور throw نوع استثنا را مشخص میکند. این عملوند میتواند هر عبارتی باشد که نتیجه آن تعیین کننده نوع استثنا خواهد بود.
در زیر مثالی از استثنا Throw هنگام مواجه با مشکل تقسیم بر صفر آورده شده است.
double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); }
گرفتن استثنا یا Catching Exceptions
بلوک catchای که پس از بلوک try میآید قادر به گرفتن هر استثنایی میباشد. میتوانید نوع استثنایی که میخواهید گرفته شود را با اعلان آن درون پرانتزهای بعد از کلید واژه مشخص کنید.
try { // protected code } catch( ExceptionName e ) { // code to handle ExceptionName exception }
کد فوق استثنایی از نوع ExceptionName را میگیرد. اگر میخواهید تعیین کنید که بلوک catch هر نوع استثنا احتمالی را دریافت کند، باید درون پرانتز … را قرار دهید.
try { // protected code } catch(...) { // code to handle any exception }
مثال زیر، یک استثنا تقسیم بر صفر پرتاب کرده و در بلوک catch گرفته میشود.
#include <iostream> using namespace std; double division(int a, int b) { if( b == 0 ) { throw "Division by zero condition!"; } return (a/b); } int main () { int x = 50; int y = 0; double z = 0; try { z = division(x, y); cout << z << endl; } catch (const char* msg) { cerr << msg << endl; } return 0; }
از آنجایی که یک استثنا از نوع *const char رخ میدهد، بنابراین حین گرفتن این استثنا، باید از *const char در بلوک catch استفاده کنیم. اگر کد بالا کامپایل و اجرا شود، خروجی زیر بدست میآید.
Division by zero condition!
استثناهای استاندارد در ++C
++C لیستی از استثناهای استاندارد در هدرفایل <exception> تعریف کرده است. این لیست در نمودار سلسله مراتبی والد-فرزند زیر نشان داده شده است.
جدول زیر توضیح مختصری از این استثناها را مهیا ساخته است.
ردیف |
استثنا و توضیح آن |
1 |
std::exception کلاس والد تمام استثناهای استاندارد در ++C است. |
2 |
std::bad_alloc ممکن است همراه با عملگر new پرتاب شود. |
3 |
std::bad_cast ممکن است همراه با عملگر dynamic_cast پرتاب شود. |
4 |
std::bad_exception این استثنا برای مدیریت استثناهای غیرمنتظره در ++C مفید است. |
5 |
std::bad_typeid ممکن است همراه با عملگر typeid پرتاب شود. |
6 |
std::logic_error استثنایی است که از لحاظ تئوری با خواندن کد قابل شناسایی است. |
7 |
std::domain_error هنگامیکه که محدوده نامعتبر ریاضی بوجود آید، این استثنا پرتاب میشود. |
8 |
std::invalid_argument این استثنا به دلیل آرگومانهای غیرمجاز پرتاب میشود. |
9 |
std::length_error این استثنا زمانی پرتاب میشود که یک std::string خیلی بزرگ ساخته شود. |
10 |
std::out_of_range این استثنا ممکن است توسط متد «at» پرتاب شود. مثلاً: std:vector و ()[]std:bitet<>::operator |
11 |
std::runtime_error استثنایی است که از لحاظ تئوری با خواندن کد قابل تشخیص نیست. |
12 |
std::overflow_error این استثنا زمانی رخ میدهد که سرریز ریاضی (mathematical overflow) رخ دهد. |
13 |
std::range_error زمانی رخ میدهد که میخواهید یک مقدار خارج از محدوده ذخیره کنید. |
14 |
std::underflow_error این استثنا زمانی رخ میدهد که پاریز ریاضیاتی (mathematical underflow) رخ دهد. |
تعریف استثناهای جدید
میتوان یک استثنای جدید را با ارث گرفتن از کلاس exception و بازنویسی توابع آن ایجاد کرد. مثال زیر نحوه استفاده از کلاس std::exception را برای پیادهسازی استثنا دلخواه به روش استاندارد نشان میدهد.
#include <iostream> #include <exception> using namespace std; struct MyException : public exception { const char * what () const throw () { return "C++ Exception"; } }; int main() { try { throw MyException(); } catch(MyException& e) { std::cout << "MyException caught" << std::endl; std::cout << e.what() << std::endl; } catch(std::exception& e) { //Other errors } }
خروجی زیر حاصل میشود.
MyException caught C++ Exception
در اینجا، ()what یک متد عمومیاست که کلاس exception آن را فراهم کرده و توسط کلاسهای فرزند بازنویسی میشود. این متد نتیجه استثنا را برمیگرداند.
منبع: ترجمه از سایت tutorialspoint.com
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.
بسیار عالی بود سپاس فراوان