נניח והמשתמש יוצר בעיה, כמו מחיקת קובץ שהתוכנה צריכה או הכנסת ערך לא תקין. בדרך כלל התוכנה שלנו תקרוס.
זה הדרך הכי פשוטה לטפל בשגיאות. אבל זה גרוע! זה מוגזם.
נניח והטייס במטוס הכניס ערך לא תקין לאחד ממערכות המטוס - האם אנחנו רוצים שהמטוס יקרוס ישר?
עוד דרך לטיפול בשגיאות היא להחזיר ערך שלא ניתן להחזיר.
בפונקציה int factorial(int n) ניתן להחזיר אם ישנה שגיאה.
אך זה גם יכול ליצור בעיות נניח עם פונקציות שבהן אין ערכים מיוחדים ובנוסף, לפעמים המשתמש לא יבדוק לערכים מיוחדים.
אופציה נוספת היא להחזיר איזשהו ובנוסף לקבל .
זה חוסם דברים כמו שרשור פונקציות(נניח שורש של שורש) וגם לא ממש טוב כי כל פונקציה צריכה לבדוק את הסטטוס הזה.
זה די מזעזע וככה עושים את זה ב-.
ישנן שלוש בעיות עיקריות בשיטה זו:
- יש סיכוי שנשכח את זה ונתעלם מהשגיאה
- כשאנו מגלים שגיאה אנו רוצים לטפל בה הכי מהר שאפשר ופה אנו צריכים לחכות שפונקציות יחזירו לפונקציות אחרות
- משרה תלות של פונקציות בפונקציות אחרות לא קשורות.
איך פותרים זאת?
זריקת שגיאות
אנו נזרוק שגיאה מהפונקציה שלנו אשר מגלה את השגיאה ובפונקציה אחרת, אשר יודעת לטפל בשגיאה, תתפוס את השגיאה.
כך, פונקציות שלא מתעסקות עם שגיאות לא יצטרכו להתעסק עם השגיאות.
אם אף אחד לא תופס את השגיאה, התוכנית תתרסק וזה באסה ואסור שיקרה.
המימוש
ישנן שתי מילים חשובות:
- נזרוק שגיאה באמצעות
- נתפוס שגיאה באמצעות בלוק
ונעשה זאת כך:
void printGradesFile(string filename)
{
ifstream infile(filename);
if (!infile)
throw string("cannot open file");
int grade;
while (infile >> grade)
cout << grade << endl;
}
int main()
{
try
{
printGradesFile("grades.txt");
}
catch (string s)
{
cerr << s << endl;
}
return 0;
}
כשאנו זורקים שגיאה הפונקציה:
- עוצרת במיידית
- לא מחזירה ערך
ניתן לתפוס מספר שגיאות בשתי צורות:
int main()
{
int a, b;
cin >> a >> b;
try
{
cout << choose(a, 4) << endl;
cout << choose(b, 4) << endl;
}
catch (int n)
{
cerr << "error no. " << n << endl;
}
return 0;
}
int main()
{
int a;
cin >> a;
try
{
cout << choose(a, 4);
}
catch (int n)
{
cerr << "error no. " << n;
}
catch (double f)
{
cerr << "other error";
}
catch (...)
{
cerr << "unknown error";
}
return 0;
}
ההבדל בין התפיסות הוא בסוג המשתנה הנזרק בלבד.
כאשר נזרקת חריגה, לכל המשתנים המקומיים נקרא ההורס באופן אוטומטי, מה שמאוד עוזר לנו שכן אנו לא נדרשים להתעסק עם מחיקת משתנים מקומיים. נדרש רק למחוק את הדברים שהקצאנו בעצמנו, מה שבדרך כלל לא נעשה כי יש לנו בנאים והורסים.
מה זורקים?
ניתן לזרוק כל דבר אפשרי אבל לרוב, מפאת העובדה שאנו תופסים לפי הסוג, נרצה לזרוק דברים משמעותיים.
class DivisonByZero {};
Rational& Rational::operator/=(const Rational& r)
{
if (r.numerator == 0)
throw DivisionByZero();
return *this *= Rational(r.denominator, r.numerator);
}
int main()
{
Rational r1(1, 2), r2(0, 1);
try
{
r1 /= r2;
cout << r1;
}
catch (DivisionByZero )
{
cerr << "oops";
}
}
ניתן להגיר כל מני סוגי שגיאות וניתן להעביר ערכים שיגידו לנו דברים על שגיאות.
class OutOfRange
{
int* data;
int size;
public:
// ... more methods ...
int size() const;
int& operator[](int index);
};
int OutOfRange::getIndex() const
{
return index;
}
OutOfRange::OutOfRange(int index) : index(index) {}
int& Array::operator[](int index)
{
if (index < 0 || index >= size)
{
throw OutOfRange(index);
}
return data[index];
}
אם שגיאה נשלחת מבנאי, האובייקט לא נבנה אך ההורס של האובייקט לא נקרא ולכן נדרש לשחרר בעצמנו את האקסטרה אחד.
class Map
{
public:
class City;
class Road;
Map();
~Map();
// ...
private:
City* cities;
Road* roads;
// ...
};
Map::Map()
{
cities = new City[INIT_CITY_NUM];
try
{
roads = new Road[INIT_ROAD_NUM];
}
catch (const bad_alloc&)
{
delete[] cities;
throw; // throws what we cought
}
// ...
}
Map::~Map()
{
delete[] cities;
delete[] roads;
}
המהדר עצמו מדי פעם שולח שגיאות. מקרים כמו הם חגיגה של שגיאות(ולפחות אנו לא צריכים לבדוק כל פעם כמו ב-)
Set::Set() : maxSize(INITIAL_SIZE), size(0), data(new int[INITIAL_SIZE]) {}
אם אנו בתוך בלוק ואנו זורקים בלי כלום, הוא זורק את השגיאה שקיבלנו.
catch (const bad_alloc&)
{
throw; // throws bad_alloc
}
לאור הדבר הזה, הורסים() הם היצור היחיד שלא יכול לזרוק שגיאות, שכן הוא הדבר היחיד שרץ במהלך שגיאות.
לא הגיוני שנזרוק חריגה עבור ניסיון הכנסת ערך לקבוצה שכבר קיים בה.
זוהי לא באמת שגיאה, אלא פשוט מצב בו אנו לא אמורים לעשות כלום.
⇐ כשאין לנו מה לעשות ב- משהו שבור בעיצוב התוכנה.