תרגול 12 standard template library כתיבת אלגוריתמים גנריים מצביעים...

52
ללללל12 Standard Template Library ללללל לללללללללל לללללל ללללללל ללללל

Post on 19-Dec-2015

229 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

12תרגול

Standard Template Libraryכתיבת אלגוריתמים גנריים

מצביעים חכמים

Page 2: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

ספרית התבניות הסטנדרטית

Cקיימת בכל מימוש של ++• ואלגוריתמים.(Containers)מכילה אוספים •

:(templates)משתמשת בתבניות •אוספי הנתונים גנריים–האלגוריתמים המסופקים גנריים–מאפשרת הרחבה ע"י המשתמש–שומרת על ביצועים גבוהים–

2

Page 3: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Vector

נכיר תחילה את האוסף הפשוט ביותר בספריה – •vector.

מערך סדור של איברים–מאפשר גישה לכל איבר באוסף–מאפשר הוספת והסרת איברים–

הערה: הקוד בשקפים הוא חלקי וחסרות בו •.STLתכונות נוספות ומתקדמות יותר של אוספי ה-

דוגמאות הקוד מתרכזות בשימוש בסיסי ופשוט.

3

Page 4: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

<vectortemplate<typename Tמתודות נבחרות של

class vector {

vector();

vector(const vector& c);

vector(size_t num, const T& val = T());

~vector();

 

T& operator[](size_t index);

const T& operator[](size_t index) const;

vector operator=(const vector& v);

 

T& at(size_t loc);

const T& at(size_t loc) const;

 

void pop_back();

void push_back(const T& val);

size_t size() const;

};

גישה בעזרת הערה:•אופרטור ][ אינה בטוחה

אינה מוודאת את •חוקיות האינדקס

לעומת זאת, גישה • זורקת )(atבעזרת

חריגה במקרה והאינדקס אינו חוקי

out_of_rangeמסוג •

4

Page 5: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

vectorדוגמאות לשימוש ב-int main() {

vector<int> v1; // empty vectorvector<int> v2(20, 8);// 20 integers, all of value 8

for(size_t i = 0; i < v2.size(); ++i) {cout << v2[i]; // Unsafe access by index

}for(int i = 0; i < 10; ++i) {

v1.push_back(i);// Inserts items at the end of the vector

}while(v1.size() > 0) {

v1.pop_back();}const vector<int> copy(v1);//Safely copies a vector

return 0;}

5

Page 6: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

יתרונות

ניהול זיכרון ע"י המחלקה•לא צריך לזכור לשחרר ידנית את המערך–ניתן לשנות את גודל המערך בקלות–ניתן ליצור העתקים ולבצע השמות בקלות–

גישה בטוחה•)(atרק כאשר משתמשים ב-–

6

Page 7: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

שאלה: כיצד ניתן ליצור וקטור בטוח?בד"כ מחיר בדיקת גישה לוקטור אינו משפיע •

על ביצועי התכנית.

ניצור גרסה של וקטור המוודאת לכל גישה •האם היא חוקית:

template<typename T>class SafeVector : public vector<T> {

SafeVector() : vector<T>() {}SafeVector(int s) : vector<T>(s) {}

T& operator[](int i) { return at(i); }const T& operator[](int i) const { return at(i); }

};

7

Page 8: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

List

דומה לוקטור, אך המימוש הוא ברשימה מקושרת.•שימוש ברשימה מקושרת מאפשר הוספת איברים מהירה –

יותר, אך אינו מאפשר גישה מהירה לאמצע האוסף.

הוא במימוש, לכן לשני vector ל-listההבדל העיקרי בין –האוספים מנשק דומה.

השימוש במנשק דומה מאפשר למשתמש להחליף בקלות –את סוג האוסף בשימוש גם בשלבים מאוחרים.

-כאמור, סיבוכיות היא שיקול משני בד"כ ולכן ניתן להשתמש בvector ,ורק בהמשך כשיש צורך ברשימה מקושרת ניתן לעבור לשימוש בה.

8

Page 9: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

listמתודות נבחרות מ-template<typename T>

class list {

list();

list(const list& c);

list(size_t num, const T& val = T());

~list();

 

list operator=(const list& v);

 

void pop_back();

void push_back(const T& val);

void pop_front();

void push_front(const T& val);

 

size_t size() const;

};

נוספו מתודות להסרת •והוספת איברים גם

בראש הרשימה

נעלמו המתודות לגישה •לאיבר באמצע

הרשימה

כיצד נוכל לאפשר •גישה למשתמש בצורה

נוחה?

9

Page 10: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Iterators.Iteratorע"מ לאפשר מעבר סדור על איברי אוסף נשתמש בעצם מסוג •

)בינתיים(:Iteratorנדרוש את הפעולות הבאות מ-•קידום – שינוי האיטרטור כך שיצביע לאיבר הבא–

קריאה – החזרת האיבר המוצבע ע"י האיטרטור–

השוואה – בדיקה האם שני איטרטורים מצביעים לאותו איבר–

איטרטור אינו מחלקה,•

.(concept)אלא מושג

למשל מצביע הוא איטרטור

:Cעבור מערך של

int* array = new int[n];...int* i = array;cout << *i << endl; // Reading the iteratori++; // Advancing the iterator by 1if (i == array+n) { // Comparing to iterators

cout << "End of array!" << endl;}

10

Page 11: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Iterators & STL

מספקים STLכל האוספים המאפשרים מעבר על איבריהם ב-•iterator.בעזרתו ניתן לעבור על איבריהם

מתאים לתחילת האוסף.iterator מחזירה )(beginהמתודה • מתאים לאיבר "דמה" אחרי iterator מחזירה )(endהמתודה •

האיבר האחרון.

למשתמש לא אכפת כיצד ממומש האיטרטור!•

11

Page 12: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

דוגמה לשימוש בוקטור

:vectorהדפסת איברי

for(vector<int>::iterator i = v.begin();i != v.end(); ++i) {

cout << *i << endl;

}

:listהדפסת איברי

for(list<int>::iterator i = l.begin(); i != l.end(); ++i) {

cout << *i << endl;

}

STLבצורה דומה ניתן לגשת לכל אוסף ב-• מוגדר בתוך כל אוסף בצורה iteratorהטיפוס עבור ה-•

הבאה:

container<int>::iterator12

Page 13: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

const_iterator

בנוסף כל אוסף מגדיר גם •.const_iteratorטיפוס

כך ניתן להגן על האוסף –מפני שינויים כאשר הוא

constמוגדר כ-

טיפוס האיטרטור המוחזר –נקבע בעזרת העמסה על

המתודות המתאימות

vector<int> v;vector<int>::iterator i = v.begin();*i = 7; // O.K.!!

// *i is int&

const vector<int> v;vector<int>::const_iterator i = v.begin();*i = 7; // syntax error!

// *i is const int&

13

Page 14: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

עוד שימושיםרוב המתודות עבור האוספים משתמשות •

באיטרטורים כדי לציין מיקומים.הוספת איבר לתוך רשימה ממוינת:–

list<double>::iterator i = myList.begin();

while (i != myList.end() && num < *i){

++i;

}

myList.insert(i, num); // Insert num before I

מחיקת האיבר החמישי בוקטור:–

myVector.erase(v.begin()+4);

14

Page 15: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

סוגי איטרטורים

אוספים שונים מחזירים איטרטורים שונים.•

bidirectional iterator, למשל, יש listל-•המאפשר קידום האיטרטור עם אופרטור++

והחזרתו לאחור עם אופרטור--.

המאפשר random access iterator יש vectorל-•גם חיבור מספרים לאיטרטור וחישוב הפרש

בין שני איטרטורים )בדומה למצביע(.

15

Page 16: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

?STLעוד

מס' רב של מתודות ואופרטורים list ו-vectorל-•נוספים.

כמעט כל פעולה שעולה בדעתכם לבצע כבר –.STLממומשת ב-

ניתן פשוט לחפש באינטרנט:– למשלhttp://www.cppreference.com/.

.STLיש עוד אוספים ב-• ומבני נתונים נוספים שלא נלמדו set, stackלמשל –

בקורס.

16

Page 17: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

כתיבת אלגוריתמים גנריים

ברצוננו לכתוב פונקציה אשר מוצאת את •האיבר המקסימלי.

כיצד נוכל לאפשר לפונקציה לעבוד על כל •אוסף אפשרי?

17

Page 18: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

maxאלגוריתם template<typename Iterator>

Iterator max(Iterator start, Iterator end) {

if (start == end) {

return end;

}

Iterator maximum = start;

for(Iterator i = ++start; i != end; ++i) {

if (*i > *maximum) {

maximum = i;

}

}

return maximum;

}

18

Page 19: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

- שימושיםmaxאלגוריתם

דוגמאות לשימוש:•מציאת הערך הגדול ביותר בוקטור.–

int m = *max(myVector.begin(), myVector.end());

מחיקת האיבר הגדול ביותר ברשימה.–myList.erase(max(myList.begin(), myList.end()));

19

Page 20: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

יתרונות

אלגוריתם יחיד מתאים לכל המקרים:•אוספים שונים–רק חלקים מהאוסף ניתנים למעבר–קל להתאים קוד קיים שיעבוד עם האלגוריתם–

למשל שימוש באלגוריתם עבור מערך רגיל שלC:

int* myArray = new int[size];

...

int m = *max(myArray, myArray+size);

20

Page 21: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

algorithm

מכיל גם אוסף STLמלבד מבני הנתונים ה-•אלגוריתמים מועילים הניתנים להפעלה על כל

מבנה נתונים מתאים:

חלקם פשוטים:•Iterator find(Iterator start, Iterator end, const T& val);

וחלקם פחות:•void sort(Iterator start, Iterator end);

void random_shuffle(Iterator start, Iterator end);

21

Page 22: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Function Objects

STLבמקום לשלוח מצביעים של פונקציות ב-•.”Function objects“משתמשים ב-

•Function object הוא כל עצם המעמיס את אופרטור )( )אופרטור ההפעלה(

22

Page 23: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

} Function Objectclass LessThanZeroדוגמה ל-

public:

bool operator()(int m) const {

return m < 0;

}

};

int main() {

LessThanZero isNegative;

 

cout << isNegative(-4) << endl; // true

cout << isNegative(6) << endl; // false

 

return 0;

}

את המחלקה מגדירים •עם אופרטור ההפעלה.

במקרה זה אנו מגדירים •את המחלקה כפונקציה

ומחזירה intהמקבלת bool.

23

Page 24: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

} Function Objectclass SumOfדוגמה ל-

public:

bool operator()(int a, int b, int s) {

return a+b == s;

}

};

int main() {

SumOf isSum;

 

cout << isSum(2,3,5) << endl; // true

cout << isSum(1,2,5) << endl; // false

 

return 0;

}

אופרטור ההפעלה ניתן •להגדרה עם כל מספר

של פרמטרים.

24

Page 25: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

} Function Objectclass LessThanדוגמה ל-

public:

LessThan(int n) : n(n) {}

  bool operator()(int m) const{

return m < n;

}

private:

int n;

};

int main() {

LessThan isLess(5);

LessThan isLess2(8);

  cout << isLess(4) << endl; // true

cout << isLess(6) << endl; // false

cout << isLess2(6) << endl; // true

  return 0;

}

עד עכשיו לא הצגנו את היתרון על •שימוש במצביע לפונקציה:

בניגוד למצביעים לפונקציות, ניתן • ולכן Function Objectלזכור מצב ב-

ניתן להשתמש באותה מחלקה למס' פונקציות השונות רק

בפרמטר כלשהו.

)היזכרו כיצד פתרנו את אותה •(Cבעיה ב-

שימו לב להבדל בין קריאה לבנאי •להפעלת האופרטור המתבצעת

על עצם מהטיפוס.

25

Page 26: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Function Objectsדוגמה - נוכל להשתמש בפונקציה שהגדרנו בקריאה •

לאלגוריתמים מסוימים:template<typename Iterator, typename Predicate>

Iterator find_if(Iterator first, Iterator last, Predicate pred) {

for (; first != last; first++)

if (pred(*first))

break;

return first;

}

vector<int> v;

vector<int>::iterator i = find_if(v.begin(),v.end(),LessThan(2));

vector<int>::iterator j = find_if(v.begin(),v.end(),LessThan(7));

26

Page 27: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Function Objectsדוגמה נוספת ל-ניצור קריטריון מיון חדש למספרים שלמים, נמיין •

:mלפי ערך המספר מודולו class LessThanModulo {

public:

LessThanModulo(int m) : m(m) {}

bool operator()(int a, int b) {return a%m < b%m;}

private:

int m;

};

בכדי למיין פשוט נקרא לאלגוריתם המיון עם •פרמטר נוסף:

sort(v.begin(), v.end(), LessThanModulo(5));

27

Page 28: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

הוספת איטרטורים

, 9 שהגדרנו בתרגול Stringניזכר במחלקת •כיצד נוכל להשתמש באלגוריתמים הקיימים

עבור מחלקה זו?

עלינו להוסיף תמיכה באיטרטורים במחלקה.•

28

Page 29: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

Stringהוספת תמיכה באיטרטורים ב-class String {

private:

int length;

char* value;

 

public:

...

  typedef char* iterator;

typedef const char* const_iterator;

 

iterator begin() { return value; }

const_iterator begin() const { return value; }

iterator end() { return value+length; }

const_iterator end() const { return value+length; }

...

};

, נוכל פשוט להשתמש Stringבמקרה של •.charבמצביע ל-

שימו לב להגדרות הטיפוסים שאנו •מוסיפים, כדי שהמשתמש לא יצטרך לדעת

charבעצמו שאנו משתמשים במצביע ל-

29

Page 30: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

שימוש

מפעיל פונקציה על תחום transformהאלגוריתם •מסוים ומציב לתחום אחר את ערך ההחזרה.

)(C toupperנשתמש בו ובפונקצית הספריה של •כדי להמיר מחרוזת לאותיות גדולות.

transform(str.begin(),str.end(),str.begin(),toupper);

30

Page 31: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

סיכום

הספריה הסטנדרטית בנויה מאוספים •ואלגוריתמים

איטרטורים מהווים את הדבק המאפשר לשני •חלקים אלו להישאר גנריים

אוספיםאוספים איטרטוריםאיטרטוריםאלגוריתמיםאלגוריתמים

31

Page 32: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

מצביעים חכמים

מצביעים אחראים לרובן המוחלט של שגיאות •הזיכרון

הצלחנו להיפטר מרוב השימושים הלא בטוחים •Cבמצביעים בעזרת שימוש בתכונות של ++

ניצול בנאים, הורסים והשמות לטיפול מסודר –בזיכרון.

ואוספים לטיפול מסודר STLשימוש ב-–באלגוריתמים של מבני הנתונים.

32

Page 33: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

בעיהvector<Shape> shapes;Circle circle(3.5);shapes.push_back(circle);// Only the "Shape part" // is copied!!

vector<Shape*> shapes;...delete shapes.back();shapes.pop_back();// We must delete ourselves// when removing items from// the vector

ירושות דורשות שימוש •במצביעים

עבודה עם מצביעים •מוחקת את כל

היתרונות שהשגנו!צריך לנהל זיכרון בצורה –

מפורשת בכל מקום בתוכנית!

33

Page 34: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

smart_ptr

נוכל ליצור מחלקה, המתנהגת כמצביע אך •מוסיפה התנהגות נוספת.

למשל, שחרור העצם המוצבע בהריסת המצביע.–

כלומר ניצור מצביע "חכם" יותר.•

34

Page 35: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

smart_ptrtemplate<typename T>

class smart_ptr {

private:

T* pointedData;

typedef T element_type;

public:

explicit smart_ptr(T* ptr = NULL) : pointedData(ptr) {}

~smart_ptr() {

delete pointedData;

}

T& operator*() const {

return *pointedData;

}

T* operator->() const {

return pointedData;

}

};

35

Page 36: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

smart_ptrיתרונות שימוש ב-

השני נכשל בכל newמה קורה במקרה וה-•אחת מהפונקציות?

int bad() {

Shape* ptr1 =

new Circle(5.0);

Shape* ptr2 =

new Square(5.0);

...

}

int good() {

smart_ptr<Shape>

ptr1(new Circle(5.0));

smart_ptr<Shape>

ptr2(new Square(5.0));

...

}36

Page 37: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

העתקה

כיצד יתנהג המצביע במקרה של העתקה?•מה צריכה להיות ההתנהגות עבור בנאי העתקה –

והשמה?

העתקת המצביע תבצע "העברת ניסיון ראשון:•בעלות" של העצם המוצבע

הקיים בספריה auto_ptrהתנהגות זו ממומשת ב-–.Cהסטנדרטית של ++

מאפשרת העברת/החזרת עצמים מוקצים דינאמית –מפונקציות.

37

Page 38: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

auto_ptrשימוש ב-

כדי להחזיר עצם חדש:auto_ptrשימוש ב-•בניגוד למצביע רגיל – מוגדר בקוד מי אחראי –

לשחרור העצם.auto_ptr<Shape> createMyShape() {

return auto_ptr<Shape>(new Circle(5.0));

}

כדי לחסוך העתקות:auto_ptrשימוש ב-•auto_ptr<vector<int>> getNPrimeNumbers (int n) {

...

}

38

Page 39: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

העתקה

auto_ptrבעיה! ההתנהגות עבור "העתקה" של •אינה סטנדרטית

ההעתק אינו זהה למקור!– לא ניתן לאחסןauto_ptr-בתוך אוספים של ה STL מאחר

והם מסתמכים על תכונה זו.

כיצד ניתן ליצור מצביע חכם שגם יאפשר •העתקה נכונה?

39

Page 40: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

שיפור – מצביע משותף

ניצור מצביע חכם יותר •shared_ptr מתקדם:

לכל עצם מוצבע נשמור •מונה הצבעות, וכל

המצביעים ישתמשו במונה זה על מנת לדעת

מתי יש לשחרר את העצם המוצבע.

ObjectObject

ObjectObject 11

22

Object* ptrint* counter

shared_ptr<Object>

Object* ptrint* counter

shared_ptr<Object> Object* ptrint* counter

shared_ptr<Object>

40

Page 41: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

משתנים ואינווריאנטהtemplate<typename T>

class shared_ptr {

private:

T* pointedData;

int* referenceCounter;

 

typedef T element_type;

 

void checkInvariant() const {

assert((pointedData &&

referenceCounter &&

(*referenceCounter)>0) ||

(!pointedData && !referenceCounter));

}

 

41

Page 42: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

עדכון המונהvoid increaseCount() {

checkInvariant();

if (referenceCounter) {

(*referenceCounter)++;

}

}

 

void decreaseCount() {

checkInvariant();

if(referenceCounter && --*referenceCounter == 0){

delete referenceCounter;

delete pointedData;

referenceCounter = NULL;

pointedData = NULL;

}

}

42

Page 43: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

אתחול ושחרורpublic:

 

explicit shared_ptr(T* ptr = NULL) :

pointedData(ptr),

referenceCounter(pointedData ? new int(1) : NULL){}

 

shared_ptr(const shared_ptr<T>& other) :

pointedData(other.pointedData),

referenceCounter(pointedData ? other.referenceCounter : NULL) {

increaseCount();

checkInvariant();

}

43

Page 44: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

אתחול ושחרורtemplate <typename S> friend class shared_ptr;

template <typename S> shared_ptr(const shared_ptr<S>& other) :

pointedData(other.pointedData),

referenceCounter(pointedData ? other.referenceCounter : NULL) {

increaseCount();

checkInvariant();

}

 

~shared_ptr() {

checkInvariant();

decreaseCount();

checkInvariant();

}

מטרת הבנאי היא •לאפשר השמה בין

shared_ptr של טיפוסים שונים,

למשל בגלל הורשה.

44

Page 45: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

גישה למצביעT& operator*() const {

checkInvariant();

assert(pointedData != NULL);

return *pointedData;

}

T* operator->() const {

checkInvariant();

assert(pointedData != NULL);

return pointedData;

}

T* get() const {

checkInvariant();

return pointedData;

}

מסופקת )(getהמתודה •בכדי לאפשר שימוש של המחלקה גם עם קוד ישן

שאינו תומך shared_ptrב-

45

Page 46: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

אופרטור השמהtemplate<typename S> shared_ptr<T>& operator=(

shared_ptr<S>& other) {

checkInvariant();

other.increaseCount();

decreaseCount();

referenceCounter = other.referenceCounter;

pointedData = other.pointedData;

checkInvariant();

return *this;

}

מה קורה במקרה של הצבה עצמית?•

מדוע אין צורך בבדיקה?•

46

Page 47: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

operator bool() {

checkInvariant();

return pointedData;

}

 

void reset() {

decreaseCount();

pointedData = NULL;

referenceCounter = NULL;

}

 

};

המרה לערך בוליאני •תאפשר לנו לבדוק האם

המצביע תקין כמו מצביע רגיל.

)(resetהמתודה •מאפשרת למשתמש

צורה נוחה יותר לאיפוס מצביע

עוד מתודות שימושיות

47

Page 48: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

פונקציות השוואהtemplate <typename T, typename S>

bool operator==(const shared_ptr<T>& first,

const shared_ptr<S>& second) {

return first.get() == second.get();

}

 

template <typename T, typename S>

bool operator!=(const shared_ptr<T>& first,

const shared_ptr<S>& second) {

return !(first==second);

}

 

template <typename T, typename S>

bool operator<(const shared_ptr<T>& first,

const shared_ptr<S>& second) {

return first.get() < second.get();

}

48

Page 49: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

דוגמאות

vector<shared_ptr<Shape> > function() {

shared_ptr<Shape> shape(new Polygon(points));

shared_ptr<Circle> circle(new Circle(5.0));

shared_ptr<Square> square(new Square(2.0));

 

vector<shared_ptr<Shape> > vec;

vec.push_back(shape);

vec.push_back(circle);

vec.push_back(square);

vector<shared_ptr<Shape> > copy = vec;

copy.pop_back();

return copy;

}

את האחרון שיוצא סוגר ההעתקות בטוחות! כל•האור!

תרגיל לבית •)למשועממים(:

מיצאו את הצורה שיש

למחוק בסוף הפונקציה...

איך היה נראה הקוד ללא •שימוש במצביעים

49חכמים?

Page 50: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

יתרונות

כל הקוד לניהול הזיכרון נכתב רק פעם אחת.•קל לחלוק עצמים אשר לא ברור מי האחרון •

שמשתמש בהם.ניתן להשתמש בכל האוספים שראינו עם •

מצביעים ובפרט עם ירושות.הקוד נהייה פשוט יותר ועמיד יותר בפני שגיאות •

זיכרון.מה קורה בדוגמה הקודמת אם אחת מהקצאות –

הזיכרון נכשלת? מה היה קורה ללא המצביעים החכמים?

50

Page 51: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

לא הכל מושלם!

•shared_ptr!אינו מתאים לאחסון מצביע למערך .][delete ולא deleteכי השחרור הוא ע"י – שיתאים לבעיה זו.shared_arrayניתן ליצור בקלות –

-אבל ממילא עדיף להשתמש בvector!

המצביעים לא ישוחררו אם קיימים קשרים •מעגליים

במקרה זה יש לנקות את המצביעים בצורה מפורשת –.resetעם

פתרון טוב יותר למקרה זה דורש היכרות עם מצביע –חכם נוסף והזמן קצר מלהכיל אותו.

51

Page 52: תרגול 12 Standard Template Library כתיבת אלגוריתמים גנריים מצביעים חכמים

לסיכום

היא מסובכת.Cכתיבת ספריות ב-++•

השימוש בהן לעומת זאת הוא פשוט.•מאפשר כתיבת קוד טוב יותר בפחות זמן ופחות שורות.–

באתר shared_ptr של פשוט מימוש למצוא ניתן•הקורס.

52