תרגול מס' 10
description
Transcript of תרגול מס' 10
![Page 1: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/1.jpg)
10תרגול מס' המחלקהStringעבודה עם קבציםתבניותחריגות
![Page 2: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/2.jpg)
2מבוא לתכנות מערכות - 234122
Stringדוגמה -
שימוש בבנאים, הורסים והעמסת אופרטורים
![Page 3: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/3.jpg)
3מבוא לתכנות מערכות - 234122
Stringדוגמה - המחלקה השימוש במחלקות, בנאים, הורסים והעמסת אופרטורים מאפשר לנו
כך שייחסכו מאיתנו החסרונות של השימוש Stringלהגדיר מחלקה עבור *charב-בזכות בנאים והורסים לא נצטרך לנהל את הזיכרון ידנית–
*, למשל גישה charבזכות העמסת אופרטורים נוכל לשמור על כל הנוחות של –כמערך
בזכות העמסת אופרטורים נוכל לאפשר פעולות בסיסיות בצורה נוחה - –למשל שרשור
![Page 4: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/4.jpg)
4מבוא לתכנות מערכות - 234122
Stringclass String {
int length;char* data;
static char* allocate_and_copy(const char* data, int size);void verify_index(int index) const;
public:String(const char* str = ""); // String s1; or String s1 =
"aa";String(const String& str); // String s2(s1);~String();int size() const;String& operator=(const String&); // s1 = s2;
![Page 5: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/5.jpg)
5מבוא לתכנות מערכות - 234122
StringString& operator+=(const String& str); // s1 += s2;const char& operator[](int index) const; // c = s1[5]char& operator[](int index); // s1[5] = 'a'
friend ostream& operator<<(ostream&,const String&); // cout << s1;
friend bool operator==(const String&, const String&); // s1==s2
friend bool operator<(const String&, const String&); // s1<s2};
bool operator!=(const String& str1, const String& str2);bool operator<=(const String& str1, const String& str2);bool operator>(const String& str1, const String& str2);bool operator>=(const String& str1, const String& str2);const String operator+(const String& str1, const String& str2);
![Page 6: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/6.jpg)
6מבוא לתכנות מערכות - 234122
Stringמימוש void error(const char* str) {
cerr << "Error: " << str << endl;exit(0);
} char* String::allocate_and_copy(const char* str, int size) {
return strcpy(new char[size + 1], str);}
פונקצית עזר סטטית,thisאין לנו כאן צורך ב-
errorבהמשך נחליף את בשימוש בחריגות
![Page 7: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/7.jpg)
7מבוא לתכנות מערכות - 234122
Stringמימוש String::String(const char* str) :
length(strlen(str)),data(allocate_and_copy(str, length)) {
}
String::String(const String& str) :length(str.size()),data(allocate_and_copy(str.data, length)) {
}
String::~String() {delete[] data;
}
int String::size() const {return length;
}
![Page 8: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/8.jpg)
8מבוא לתכנות מערכות - 234122
Stringמימוש String& String::operator=(const String& str) {
if (this == &str) {
return *this;
}
delete[] data;
data = allocate_and_copy(str.data, str.size());
length = str.length;
return *this;
}
String& String::operator+=(const String& str) {
char* new_data = allocate_and_copy(data, str.size() + size());
strcat(new_data, str.data);
delete[] data;
length += str.length;
data = new_data;
return *this;
}
![Page 9: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/9.jpg)
9מבוא לתכנות מערכות - 234122
Stringמימוש void String::verify_index(int index) const {
if (index >= size() || index < 0) {error("Bad index");
}return;
} const char& String::operator[](int index) const {
verify_index(index);return data[index];
} char& String::operator[](int index) {
verify_index(index);return data[index];
}
& צריכות פונקציות המחזירות בדרך כלל שתי גרסאות - עבור עצמים רגילים ועבור
קבועים
![Page 10: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/10.jpg)
10מבוא לתכנות מערכות - 234122
Stringמימוש bool operator==(const String& str1, const String& str2) {
return strcmp(str1.data, str2.data) == 0;} ostream& operator<<(ostream& os, const String& str) {
return os << str.data;} bool operator<(const String& str1, const String& str2) {
return strcmp(str1.data, str2.data) < 0;}
![Page 11: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/11.jpg)
11מבוא לתכנות מערכות - 234122
Stringמימוש bool operator!=(const String& str1, const String& str2) {
return !(str1 == str2);} bool operator<=(const String& str1, const String& str2) {
return !(str2 < str1);} bool operator>(const String& str1, const String& str2) {
return str2 < str1;} bool operator>=(const String& str1, const String& str2) {
return str2 <= str1;} const String operator+(const String& str1, const String& str2) {
return String(str1) += str2;}
![Page 12: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/12.jpg)
12מבוא לתכנות מערכות - 234122
Stringדוגמה - קוד המשתמש ב-
int main(int argc, char **argv) {
String s = "So long";
String s2 = "and thanks for all the fish.";
String sum = s + " " + s2;
sum[sum.size() - 1] = '!';
cout << sum << endl;
return 0;
}
* charכל האפשרויות הקיימות עבור נתמכות במחלקה החדשה רק כעת
אין צורך בניהול זיכרון מפורש
![Page 13: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/13.jpg)
13מבוא לתכנות מערכות - 234122
std::string-קובץ הheader string מהספריה הסטנדרטית שלC מכיל מימוש של ++
אשר תומכת בכל הפעולות שמימשנו כאן ועוד std::stringהמחלקה
להשתמש ב-הקפידוstd::string-ולא ב char *++-עבור מחרוזות בC
![Page 14: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/14.jpg)
14מבוא לתכנות מערכות - 234122
עבודה עם קבצים
המחלקותofstream-ו ifstream
![Page 15: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/15.jpg)
15מבוא לתכנות מערכות - 234122
++Cקלט/פלט עם קבצים ב-
-כמו בC-גם ב C הטיפול בקבצים דומה לטיפול בערוצי הקלט/פלט ++הסטנדרטיים
-בC עבודה עם קבצים מתבצעת בעזרת מחלקות המוגדרות בקובץ ++fstream
המחלקהofstream משמשת לכתיבה לקובץ המחלקהifstream משמשת לקריאה מקובץ שם הקובץ לפתיחהלשתי המחלקות יש בנאי המקבל את כאשר העצם נהרסהמוודא שהקובץ נסגר לשתי המחלקות יש הורסכמו עבור ערוצים >> ו-<< מתבצעות על ידי שימוש ב-קריאה והדפסה
רגילים כמתודות של שאר הפעולות הדרושות על ערוצי הפלט מבוצעות
המחלקות מחזירה חיווי האם הגענו לסוף הקובץeofלמשל המתודה –
![Page 16: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/16.jpg)
16מבוא לתכנות מערכות - 234122
קלט/פלט עם קבצים - דוגמה#include <fstream>using std::ifstream;using std::ofstream;using std::cerr;using std::endl;
void copyFile(const char* fromName, const char* toName) {ifstream from(fromName);if (!from) {
cerr << "cannot open file " << fromName << endl;return;
}ofstream to(toName);if (!to) {
cerr << "cannot open file " << toName << endl;return;
}while (!from.eof()) {
char c;from >> c;to << c;
}}
למה לא צריך לסגור את הקובץ?
boolהמרה ל-
![Page 17: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/17.jpg)
17מבוא לתכנות מערכות - 234122
תבניות
תבניות של פונקציותתבניות של מחלקות
![Page 18: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/18.jpg)
18מבוא לתכנות מערכות - 234122
תכנות גנרי
נניח שברצוננו לכתוב פונקציה למציאת המקסימום במערך של עצמיםלכל טיפוס נצטרך לרשום מחדש פונקציה כמעט זהה–
של פונקציות המוצאות מקסימום במערךהתבנית הכללית קל לנו לראות את(string ו-intמשתנה )בדוגמאות שלנו שם הטיפוס רק –
שיתאים לכל טיפוסקוד גנרי ברצוננו לכתוב? מה היו החסרונות בשיטה זו?Cכיצד עשינו זאת ב-–
int max(const int* array, int size) {
int result = array[0];for (int i = 1; i < size;
++i) {if (result <
array[i]) {result =
array[i];}
}return result;
}
string max(const string* array, int size) {
string result = array[0];for (int i = 1; i < size; ++i) {
if (result < array[i]) {result =
array[i];}
}return result;
}
![Page 19: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/19.jpg)
19מבוא לתכנות מערכות - 234122
תבניות קוד התלוי בפרמטרים של זמן הקומפילציהתבניות של קוד ניתן לכתוב - כדי להגדיר תבנית לפונקציה משתמשים במילה השמורהtemplate לפני הגדרת
על הפרמטרים של התבנית:> < הפונקציה ומכריזים בתוך
הקומפיילר ישתמש בתבנית כדי ליצור קוד במקרה הצורךתהליך יצירת מופע של הקוד המוגדר על ידי התבנית מתבצע בזמן הקומפילציה –
instantiationוקרוי
בקבצי תבניות יש להגדיר תמידhכך שיהיו זמינות לקומפיילר
template<class T>T max(const T* array, int size) {
T result = array[0];for (int i = 1; i < size;
++i) {if (result <
array[i]) {result =
array[i];}
}return result;
}
ניתן להשתמש במילה במקום typenameהשמורה
classב- מייצג שם Tבתוך קוד התבנית
של טיפוס וניתן להשתמש בו כמו בשם של טיפוס רגיל: Tלהכריז על משתנים מסוג
ולבצע עליהם פעולות
![Page 20: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/20.jpg)
20מבוא לתכנות מערכות - 234122
תבניות - שימוש
כדי להשתמש בפונקציה המוגדרת על ידי תבנית ניתן לקרוא לה לפישמה ובתוספת הפרמטרים הדרושים לתבנית:
ניתן לקרוא לפונקציה ללא ציון הפרמטרים לתבנית - במקרה זההקומפיילר יסיק אותם בעצמו
במקרה זה הפונקציה משתתפת בשלב פתרון ההעמסה יחד עם פונקציות –נוספות
int array[] = {4, -1 ,2};
string array2[] = {"Hello", "cruel", "world"};
cout << max<int>(array, 3) << endl;
cout << max<string>(array2, 3) << endl;
int array[] = {4, -1 ,2};
string array2[] = {"Hello", "cruel", "world"};
cout << max(array, 3) << endl;
cout << max(array2, 3) << endl;
array הוא int ולכן תיקרא *max<int>
array2 הוא string ולכן תיקרא *max<string>
![Page 21: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/21.jpg)
21מבוא לתכנות מערכות - 234122
תבניות והעמסת פונקציות
:בפתרון העמסה אשר מעורבות בו תבניותמאשר שימוש מתאימה בדיוק לפרמטרים הקומפיילר יעדיף פונקציה אשר –
בתבנית )על ידי הסקת טיפוסים(
הקומפיילר יעדיף שימוש בתבנית על שימוש בהמרות–
כדי להתאים לתבניתלא יבצע המרות אוטומטיות הקומפיילר –
ניתן להכריח שימוש בפונקצית תבנית על ידי ציון הפרמטרים לתבנית במפורש–
![Page 22: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/22.jpg)
22מבוא לתכנות מערכות - 234122
תבניות - העמסת פונקציות
:דוגמאות
template<class T>
T max (T a , T b , T c ) {
if (a > b && a > c) return a ;
if (b > c) return b ;
return c;
}
// ...
int j = max(1,3,3); //
char c = max ('w','w','w'); //
String s = max (s1,s2,s3); //
int j = max (1,'a','a'); //
int j = max<int> (1,'a','a'); //
int max(int a , int b , int c ) {
if (a > b && a > c) return a ;
if (b > c) return b ;
return c;
}
// ...
int j = max (1,3,3); //
char c = max ('w','w','w');//
String s = max (s1,s2,s3); //
int j = max (1,'a','a'); //
![Page 23: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/23.jpg)
23מבוא לתכנות מערכות - 234122
תבניות - יצירת מופעים
כאשר הקומפיילר משתמש בתבנית הוא מנסה ליצור פונקציה לפיהתבנית על ידי החלפת הפרמטרים לתבנית
בערכים שהועברו לה.האם תהליך זה יכול להיכשל?–
בכדי שהשימוש בתבנית יצליח על הארגומנטים המועברים לתבנית לעמודבדרישות הלא מפורשות על הטיפוס המופיעות בקוד
?max ב-Tאילו דרישות יש על הטיפוס –
template<class T>T max(const T* array, int size) {
T result = array[0];for (int i = 1; i < size;
++i) {if (result <
array[i]) {result =
array[i];}
}return result;
}Stack array[] = {Stack(50), Stack(60), Stack(70)};cout << max(array, 3) << endl;
![Page 24: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/24.jpg)
24מבוא לתכנות מערכות - 234122
מחלקות גנריות
ניתן להגדיר תבנית עבור מחלקה ובכך לממש מחלקות גנריות בדומהCל-והקומפיילר יוודא את לא נצטרך לשלוח מצביעים לפונקציות Cבניגוד ל-–
<template <class T בעצמונכונות הטיפוסיםclass Array {
T* data;int size;
public:explicit Array(int size);Array(const Array& a);~Array();Array& operator=(const Array&
a);int size() const;T& operator[](int index);const T& operator[](int index)
const;};
בתוך ההכרזה על המחלקה במקום Arrayניתן לרשום
Array<T>
![Page 25: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/25.jpg)
25מבוא לתכנות מערכות - 234122
מחלקות גנריות
בניגוד לפונקציות, עבור מחלקות חייבים לרשום במפורש אתהקומפיילר לא יכול להסיק אותם בעצמוהארגומנטים לתבנית -
טיפוס חדשכל שימוש בתבנית עם ארגומנטים אחרים יוצר
void f(Array<string>& words) {
Array<int> numbers(100);
for(int i = 0; i < numbers.size(); ++i) {
numbers[i] = i;
}
words = numbers; // error, type mismatch
}
![Page 26: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/26.jpg)
26מבוא לתכנות מערכות - 234122
++Cמחסנית גנרית ב-template <class T = int>class Stack {
T* data;int size;int nextIndex;
public:Stack(int size = 100);Stack(const Stack& s);~Stack();Stack& operator=(const Stack&);void push(const T& t);void pop();T& top();const T& top() const;int getSize() const;
};
:נשפר את המחסנית שלנו כך שתהיה גנריתניתן לתת ערך ברירת מחדל, כמו בערכי ברירת מחדל של
פונקציות
![Page 27: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/27.jpg)
27מבוא לתכנות מערכות - 234122
++Cמחסנית גנרית ב-template <class T>Stack<T>::Stack(int size) :
data(new T[size]), size(size), nextIndex(0) {} template <class T>Stack<T>::Stack(const Stack<T>& s) :
data(new T[s.size]), size(s.size), nextIndex(s.nextIndex) {for (int i = 0; i < nextIndex; ++i) {
data[i] = s.data[i];}
} template <class T>Stack<T>::~Stack() {
delete[] data;}
![Page 28: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/28.jpg)
28מבוא לתכנות מערכות - 234122
++Cמחסנית גנרית ב-template <class T>
Stack<T>& Stack<T>::operator=(const Stack<T>& s) {
if (this == &s) {
return *this;
}
delete[] data;
data = new T[s.size];
size = s.size;
nextIndex = s.nextIndex;
for (int i = 0; i < nextIndex; ++i) {
data[i] = s.data[i];
}
return *this;
}
![Page 29: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/29.jpg)
29מבוא לתכנות מערכות - 234122
++Cמחסנית גנרית ב-template <class T>void Stack<T>::push(const T& t) {
if (nextIndex >= size) {error("Stack full");
}data[nextIndex++] = t;
} template <class T>void Stack<T>::pop() {
if (nextIndex <= 0) {error("Stack empty");
}nextIndex--;
}
![Page 30: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/30.jpg)
30מבוא לתכנות מערכות - 234122
++Cמחסנית גנרית ב-template <class T>T& Stack<T>::top() {
if (nextIndex <= 0) {error("Stack empty");
}return data[nextIndex - 1];
} template <class T>const T& Stack<T>::top() const {
if (nextIndex <= 0) {error("Stack empty");
}return data[nextIndex - 1];
}
template <class T>int Stack<T>::getSize() const {
return size;}
![Page 31: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/31.jpg)
31מבוא לתכנות מערכות - 234122
שימוש במחסנית הגנריתint main() {
Stack<int> s;
Stack<string> s2;
s.push(20);
s2.push("Hello");
Stack s3(s);
s3 = s2; // error
cout << s.top() << s2.top() << endl;
return 0;
}
למה מתקבלת שגיאה?
![Page 32: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/32.jpg)
32מבוא לתכנות מערכות - 234122
תבניות - פרמטרים
ניתן להגדיר תבניות המקבלותיותר מפרמטר אחד
Pair<char, double> p('a', 15.0);
cout << "(" << p.first << "," << p.second << ")";
template<class T, class S>
struct Pair {
T first;
S second;
Pair(const T& t, const S& s)
: first(t), second(s) {}
};
List<Pair<string, int> > phonebook;
phonebook.add(Pair<string, int>("Dani",8343434));
phonebook.add(Pair<string, int>("Rami",8252525));
הרווח הזה הוא חובה
![Page 33: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/33.jpg)
33מבוא לתכנות מערכות - 234122
תבניות - פרמטרים
ניתן להגדיר תבניות גם עבור פרמטרים מטיפוסint:למשל ,template<class T, int N>class Vector {
T data[N];public:
Vector();Vector& operator+=(const
Vector& v);//...
}; void f(Vector<int, 3>& v) {
Vector<int, 5> v5;Vector<int, 3> v3;v3 += v; // o.k.v5 += v; // error
}
,Vector<intהמספר הוא חלק מהטיפוס, לכן < הם טיפוסים שוניםVector<int, 5< ו-3
נסיון לחבר וקטורים ממימדים לא יתקמפלשונים
N נקבע בזמן הקומפילציה, לכן אנו מגדירים למעשה מערך בגודל קבוע
כשדה במחלקה
![Page 34: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/34.jpg)
34מבוא לתכנות מערכות - 234122
תבניות - שגיאות קומפילציהכאשר הקומפיילר עובר על תבנית הוא יכול למצוא בה רק שגיאות בסיסיות של תבנית יתגלו שגיאות התלויות בארגומנט יוצר מופע כאשר הקומפיילר
הספציפיהשגיאה המתקבלת מהקומפיילר תהיה מורכבת ממספר שורות ותכלול את רשימת –
התבניות והארגומנטים שלהן
ורק אחרי שהוא מומלץ לכתוב תחילה קוד רגיל בגלל השגיאות המסובכותעובד להמיר אותו לתבנית
void f() {Stack<Pair<int, int> >
ranges(10);}..\main.cpp: In constructor `Stack<T>::Stack(int) [with T = Pair<int, int>]':
..\main.cpp:241: instantiated from here
..\main.cpp:108: error: no matching function for call to `Pair<int, int>::Pair()'
..\main.cpp:233: note: candidates are: Pair<int, int>::Pair(const Pair<int, int>&)
..\main.cpp:237: note: Pair<T, S>::Pair(T, S) [with T = int, S = int]
![Page 35: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/35.jpg)
35מבוא לתכנות מערכות - 234122
תבניות - סיכום
ניתן להגדיר תבנית לפונקציה-ניתן להגדיר מחלקות גנריות בעזרת שימוש בtemplate-בניגוד לCכל בדיקות הטיפוסים נעשות בזמן קומפילציה כדי שהשימוש בתבנית יתקמפל על הארגומנטים המועברים לתבנית
להיות בעלי כל התכונות הדרושות לפי התבניתניתן להגדיר תבניות שהפרמטרים שלהן הם מספריםניתן להגדיר תבניות עם מספר פרמטרים מומלץ לכתוב תחילה קוד ללא תבניות ולהמירו אח"כ כדי למנוע
התמודדות עם פלט מסובך מהקומפיילר
![Page 36: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/36.jpg)
36מבוא לתכנות מערכות - 234122
חריגות
-שימוש בtry, catch-ו throwהקצאה על ידי אתחול
![Page 37: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/37.jpg)
37מבוא לתכנות מערכות - 234122
חריגות
מנגנון החריגות עובד בעזרת שלושת המילים השמורותthrow, try:-ו catch–throwמקבלת כפרמטר את העצם אותו יש לזרוק כחריגה :
–tryמציינת תחילה של בלוק אשר ייתכן ותיזרק ממנו חריגה שנרצה לתפוס :
–catchמציינת סוג חריגה לתפוס ואת הקוד המתאים לטיפול בחריגה :
כאשר נזרקת חריגה הקוד הרגילומתחילה יציאהמפסיק להתבצע
מכל פונקציה בתכנית עד אשרהחריגה מטופלת
בכלללא מטופלת אם חריגההתכנית תסתיים( main)נזרקת מ-
void f(int n) {if (n < 0) {
throw -1;}
} int main(int argc, char **argv) {
try {f(-7);
} catch (int e) {cerr << "Error: "
<< e << endl;}
}
![Page 38: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/38.jpg)
38מבוא לתכנות מערכות - 234122
חריגות
:כאשר חריגה נזרקת מתבצעים הדברים הבאיםקוראים להורסים של המשתנים המקומיים tryלא בתוך בלוק כל עוד אנחנו –
ויוצאים מהפונקציה
לסוג החריגה הקיים מתאים catchקיים בודקים האם tryאם אנחנו בבלוק –
אם לא, קוראים להורסים וממשיכים לצאת•
ולאחריו הפונקציה ממשיכה catchמתבצע הקוד בבלוק ה-אם כן, • האחרוןcatchמהשורה שאחרי בלוק ה-
עבור טיפוסים שוניםcatchייתכנו מספר בלוקים של •
התרת המחסניתתהליך היציאה מפונקציות עד לתפיסת שגיאה נקרא(stack unwinding)בין זריקת החריגה ועד לתפיסתה הקוד היחיד שמתבצע הוא של הורסים של –
המשתנים המקומיים המשוחררים
![Page 39: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/39.jpg)
39מבוא לתכנות מערכות - 234122
חריגות השימוש בחריגות מונע כתיבה מיותרת של קוד עבור
טיפול בשגיאות בכל פונקציה בדרךמי שיודע למצוא את השגיאה זורק חריגה–
רק מי שיודע לטפל בשגיאה מתייחס אליה–
-בשימוש בקודי שגיאה כמו בC הטיפול במקרי למרבית הקודהשגיאה נהפך
-בC אבל נהוג לזרוק כל עצם שהוא ++ ניתן לזרוקכדי לציין שגיאות מחלקות שנוצרו במיוחד רק
ספציפיות
void f(int n) {if (n < 0) {
throw -1;
}}
void g(int n) {f(-n);
}
void h(int n) {g(2*n);
}
int main() {try {
h(7);} catch (int e)
{cerr <<
"Error: " << e;}
}
main
h g f
call call call
return return return
throw
![Page 40: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/40.jpg)
40מבוא לתכנות מערכות - 234122
חריגות
:נוסיף חריגות למחסנית הגנרית שלנוtemplate<typename T>class Stack {
T * data;int size;int nextIndex;
public:
Stack(int size = 100);Stack(const Stack&
stack);~Stack();Stack& operator=(const
Stack& s);void push(const T& t);void pop();T& top();const T& top() const;int getSize() const;
class Full {};class Empty {};
};
template<typename T>void Stack::push(const T& t) {
if (nextIndex >= size) {throw Full();
}data[nextIndex++] = t;
} template<typename T>void Stack::pop() {
if (nextIndex <= 0) {throw Empty();
}nextIndex--;
}
ניתן להגדיר מחלקות בתוך מחלקות
![Page 41: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/41.jpg)
41מבוא לתכנות מערכות - 234122
חריגות - שימוש במחסנית
במספר משפטי ניתן להשתמשcatch עבור tryיחיד
-כדי לתפוס כל ...ניתן להשתמש ב חריגה
במקרה זה לא ניתן לגשת לחריגה –שנתפסה
אם כמה מקרים מתאימים לתפיסתהחריגה ייבחר הראשון שמופיע
אחרוןלכן ... תמיד מופיע –
-ניתן לזרוק חריגה מחדש מcatch ללא פרמטרים throwעל ידי
void f(Stack<int>& s) {try {
s.pop();for (int i = 0; i
< 10; ++i) {
s.push(i);}
} catch (Stack<int>::Empty& e) {
cerr << "No numbers";
} catch (Stack<int>::Full& e) {
cerr << "Not enough room";
} catch (...) {cerr << "Oops";throw;
}}
![Page 42: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/42.jpg)
42מבוא לתכנות מערכות - 234122
חריגות
חריגות יכולות להיותיותר מורכבות
למשל ניתן לשלוח בהןמידע מדויק על
השגיאה
class String::BadIndex {public:
int index;BadIndex(int index) : index(index) {}
};
void String::verify_index(int index) const {if (index >= size() || index < 0) {
throw BadIndex(index);}return;
}
const char& String::operator[](int index) const {
verify_index(index);return data[index];
}
char& String::operator[](int index) {verify_index(index);return data[index];
}
בשביל להגדיר מחלקה מקוננת כך יש להכריז
Stringעליה בתוך
void f(String& s) {try {
cout << s[50];} catch
(String::BadIndex& e) {cerr << "Bad
Index: "<<
e.index;}
}
![Page 43: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/43.jpg)
43מבוא לתכנות מערכות - 234122
חריגות
חריגות מבנאיניתן לזרוק:
לזרוק חריגות מהורסמסוכן:יכולה להיות רק חריגה אחת בו זמנית–
בזמן זריקת חריגה הורסים ממשיכים להתבצע–
אם נזרקת חריגה נוספת התכנית תתרסק–
כאשר הקצאת זיכרון על ידיnew נכשלתstd::bad_allocנזרקת חריגה מסוג
Rational::Rational(int n, int d) :
num(num), denom(denom) {
if (denom == 0) {throw
DivideByZero();}
}
int main() {try {
while (true) {
new int[1000000];
}} catch
(std::bad_alloc& e) {cerr << "Out
of memory";}return 0;|
}
![Page 44: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/44.jpg)
44מבוא לתכנות מערכות - 234122
קוד בטוח לחריגות
לחריגות יש חיסרון חשוב - כל קריאה בקוד שלנו עלולה לגרום לזריקתחריגה )בצורה ישירה או עקיפה( ולכן הקוד צריך להיות מוכן לזריקת
חריגה בכל שלב לדוגמה, מה הבעיה באופרטור ההשמה שלString?שלנו char* String::allocate_and_copy(const char* str, int
size) {return strcpy(new char[size+1], str);
}
String& String::operator=(const String& str) {if (this == &str) {
return *this;}delete[] data;data = allocate_and_copy(str.data, str.size());length = str.length;return *this;
}
![Page 45: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/45.jpg)
45מבוא לתכנות מערכות - 234122
קוד בטוח לחריגות
כאשר מבצעים קוד של שחרור והקצאות - קודם מבצעים את החלקהבעייתי ואח"כ את שחרור המידע הישן:
?עדיין קיימת בעיה - מה קורה אם יש שתי הקצאות בבת אחת
char* String::allocate_and_copy(const char* str, int size) {
return strcpy(new char[size+1], str);}
String& String::operator=(const String& str) {
char* temp = allocate_and_copy(str.data, str.size()); delete[] data;
data = temp;
length = str.length;
return *this;
}
למה לא צריך בדיקת השמה עצמית?
![Page 46: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/46.jpg)
46מבוא לתכנות מערכות - 234122
הקצאת משאבים על ידי אתחולResource Acquisition is Initialization
לעטוף את כל כדי להתמודד עם הסכנות הלא צפויות של חריגות נהוגהקצאות המשאבים במחלקות
בשיטה זו ההורס של המחלקה אחראי לנקות–
, בפרט בזמן התרת המחסניתאוטומטיתהורסים נקראים –
התעסקות מייגעת בהקצאות השימוש בשיטה זו חוסך למתכנת} ()void badושחרורים
char* str1 = new char[N+1];
try {char* str2 =
new char[N+1];// ... code ...
} catch (bad_alloc& e) {
delete[] str1;}
}
void good() {string str1;string str2;// ...
code ...}
![Page 47: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/47.jpg)
47מבוא לתכנות מערכות - 234122
חריגות -שימוש נכון
משתמש בחריגות כבערכי חזרההמנעו מכתיבת קוד אשרהמנעו משימוש בחריגות לשם שליטה בקוד
המנעו מלהכריח את המשתמשים בקוד שלכם לעשות זאת–
void bad(Stack<int>& s) {while(true) {
try {cout <<
s.top() << endl;s.pop();
} catch (Stack<int>::Empty& e) {
break;}
}}
void good(Stack<int>& s) {while(s.getSize()
> 0) {cout <<
s.top() << endl;s.pop();
}}
![Page 48: תרגול מס' 10](https://reader036.fdocuments.net/reader036/viewer/2022081504/56814039550346895daba735/html5/thumbnails/48.jpg)
48מבוא לתכנות מערכות - 234122
חריגות - סיכום
-טיפול בשגיאות מתבצע בC בעזרת ++throw, try-ו catchאפשר לזרוק כל דבר אבל נהוג לזרוק רק עצמים ממחלקות ייעודיותהשתמשו בחריגות כדי לאפשר לבנאי להיכשל שגיאות מהספריה הסטנדרטית, כמו כשלון שלnew מטופלות על ידי
חריגותכדי לשמור על קוד בטוח לחריגות עטפו הקצאות משאבים במחלקותהמנעו מכתיבת קוד אשר משתמש בחריגות כבערכי חזרה