איטרטורים

gmorphus

New member
איטרטורים

יצא לי הרבה לעבוד עם STL ועם האיטרטורים שלו, אבל עכשיו עלתה בי תהיה: מה קורה האיטרטור שלי מצביע למקום מסוים ברשימה, ואז אני מוחק את אותו איבר (נניח שלא דרך האיטרטור)? איך הSTL מתמודד עם זה? בדקתי את זה וראיתי שתוכנית לא קורסת או משהו כזה... אבל בכל זאת?
 

voguemaster

New member
תלוי בסוג ה-container

יש כאלו שיודעים להתמודד עם זה ויש כאלו שבהם האיטרטור הופך ל-non valid, כלומר אם תשתמש בו אתה עלול לקבל מה שנקרא undefined behavious...
 

gmorphus

New member
ברור לי שזה תלוי...

נגיד בווקטור אני חושב שזה עדיין יהיה תקין, אבל list לעומת זה לא ממש עובד. הרי אתה פשוט מוחק את המצביע ואז האיטרטור שבו לא נגעת הופך לחסר משמעות. אז מה אם כן קורה? ולמה התוכנית לא קורסת לי?
 

vinney

Well-known member
הכי פשוט

תעשה TRACE. מה שטוב ב STL זה שיש לך את כל הSOURCEים
פשוט תראה מה קורה שם
אני מניח שחשבו על זה לפנייך, ויש שם הגנות למצבים כאלה (איפה שאפשר להגן, לא תמיד אפשר...) במקרה של וקטור, למשל, האיטרטור יכול לדלג לאיבר הבא, או ל END (גם הוא איטרטור) אם הוקטור מתרוקן.
 

the new L

New member
מה??

איך אתה יכול להגיד שב STL יש את הSOURCES??? הרי לפי התקן קבצים כמו <vector< אפילו לא חייבים להיות באמת קיימים אלא יכולים למשל להיות ממומשים כחלק מהקומפיילר...
 

vinney

Well-known member
המם.... הם קיימים

אצלי לפחות (VISUAL STUDIO 6 LEARNING EDITION), וגם בקומפיילרים אחרים שעבדתי איתם (בUNIX בעיקר). נכון שאפשר שלא יהיו, אבל קומפיילר שממש את זה hardcoded זה קומפיילר מאוד מאוד טיפש
.
 

gmorphus

New member
להגיד פשוט על הקוד של STL

זה לא הולך ביחד באותו משפט
הסתכלתי בקוד, אבל הפואנטה שלי היא שיש לי משתנה שהוא איטרטור שמאותחל ל list.begin. עכשיו אני מוחק את האיבר הראשון מהרשימה שלי באמצעות pop_front האיטרטור עצמו לא השתנה אולם הערכים שהוא מצביע אליהם כרגע חסרי משמעות. למה כאשר אני מנסה לגשת למקום הזה הקומפיילר לא צועק? האם יכול להיות שSTL לא באמת משחרר את המקום? (קשה לי להאמין) על פי העיון הקצר שלי בקוד נראה כאילו המקום באמת משוחרר... בקיצור מה באמת הולך שם?
 

vinney

Well-known member
המם....

איטרטור במקרה הזה הוא כמו מצביע. אתה עושה delete/free למצביע, הוא הופך להיות NULL/לא תקין. אתה יכול לגשת אליו שורה הבאה, וקומפיילר לא יצעק, זאת שגיאת זמן ריצה (מהנפוצות יותר). כשאתה עושה pop_front, אתה מוריד את האובייקט מהרשימה, אבל האיטרטור מצביע על האובייקט (שקיבל בהשמה ל list.begin שמחזיר את האובייקט הראשון ברשימה באותו רגע), ולא על הרשימה, והאובייקט עצמו חי וקיים (כי הרי לא עשית לו delete), ולכן האיטרטור שלך בסדר. גם אם תעשה לו delete, אגב, הקומפיילר לא יצעק, כי זאת שגיאת זמן ריצה.
 

gmorphus

New member
נראה כאילו אתם לא שמים ../images/Emo23.gif למה

שאני אומר. אני לא מדבר על צעקה של הקומפיילר!!! אין לו מה לצעוק ואני גם לא מחפש את זה. מה שאמרתי זה שעשיתי משהו כזה:
list<int> l; l.push_back(1); list<int>::iterator it = l.begin(); int temp = *it; // here it is ok l.pop_front(); temp = *it; // meaning less value - // but the program didn't crush!
כמו שאפשר לראות אין קשר בין האיטרטור למחיקה של האיבר (אלדד!) אבל התוכנית לא קורסת ועדיין הערך לא תקין. אני מכיר STL די טוב (לא מספיק כנראה) ואני יודע שlist זה פשוט רשימה מקושרת ואיטרטור של list מכיל פשוט מצביע... אני טוען שבפקודה pop_front מתבצעת מחיקה של האיבר בפועל (באמצעות delete) - אבל עדיין לא קרה שום דבר הרה אסון לתוכנית (בזמן ריצה!).​
 

vinney

Well-known member
שמים גם שמים

תשמע... א. pop_front לא מבצע delete. מהטעם הפשוט שSTL (כשמה כן הוא) היא ספריה של תבניות, ותבנית לא יודעת אם הפרמטר שתתן יהיה מצביע או (כמו במקרה שלך) לא. ב. לגבי התוכנית הספציפית שלך, היא שווה לזה: int *i int j= *i התוכנית הזאת תעבוד מצוין. מכיוון שלא מדובר במשתנים גלובליים, יהיה ב i איזשהו זבל שונה מNULL (רוב הסיכויים לפחות), כך שj יקבל ערך שהזבל מצביע אליו. האם זה ערך תקין? לא. האם זה תקין מבחינת שגיאות זמן ריצה של התוכנית? בוודאי.
 

DadleFish

New member
לא, לא

pop_front כנראה כן מבצעת delete - מדובר ב-delete הפנימי שהיא עושה לעצמה, בתור רשימה. זה שקוף לך ולא צריך לעניין אותך. גם ההקבלה שלך ל- i ו-j לא נכונה. זה פשוט לא אותו דבר.
 

vinney

Well-known member
לא הבנת

הכוונה ל delete של האובייקט המקורי. מה קורה שם בפנים לא מעניין אף אחד. ולגבי I ו J, אז זה הקבלה קיצונית, נכון שזה לא אותו דבר, אבל זה אותה תוצאה.
 

DadleFish

New member
טוב,

הציפיות שלך פשוט מוגזמות
נתחיל מזה שאתה לא יכול לצפות שאיטרטור כלשהו יקבל דיווח על זה שעשית מחיקה שלא קשורה אליו בכלל. שנית, זה נכון - איטרטור הוא כנראה מצביע (המימוש לא מחוייב לך הרי, רק ה-API). זה שפנית אליו ולא קרה שום אסון, זה עניין של מזל. תחשוב ככה - נגיד שיש לך רשימה מקושרת. איבר במיקום 1000 מצביע על איבר במיקום 2000 שמצביע על איבר במיקום 3000. עכשיו הסרת את 2000 ברשימה, כלומר עשית לו delete ועדכנת את שני האיברים האחרים בדבר השינוי (נגיד רשימה דו כיוונית). אם תנסה עכשיו לקחת את הערך מ-2000, רוב הסיכויים שהוא עדיין יהיה שם, אם מדובר בפעולה שמתבצעת מייד אחרי ה-delete. הרי delete לא טורח לנקות את הזכרון - זה סתם בזבוז זמן! לכן התוכנית שלך לא עפה, אבל היא גם לא מתפקדת טוב.
 

gmorphus

New member
../images/Emo49.gif אלדד הבין ../images/Emo13.gif

וויני, אין קשר בין מה שאתה אומר לשאלה שלי. גם התוכנית הקטנה שאתה הצגת אמורה לגרום לשגיאה בזמן ריצה כי אתה עלול לנסות לגשת לזיכרון שלא שלך. חוץ מזה, אני מדבר על מחיקה של החוליה ברשימה המקושרת כמו שאלדד הסביר ולא של האובייקט עצמו שנמצא ברשימה. זה הרי אפילו לא אפשרי במקרה הזה כי הוא int... אלדד, אני ממש לא מצפה שהוא יעדכן את האיטרטור (ואוי ואבוי לו אם הוא יעשה את זה כי לא ביקשתי את זה ממנו בכלל). ברור לי שDELETE לא מנקה את הזיכרון... בכל מקרה, די ענית לי לשאלה: הם לא מתמודדים עם הבעיה הזאת (וגם לדעתי לא ממש צריך) וזה שלא קרסה לי התוכנית זה במקרה... ואני לא אמור להתנהג ככה עם איטרטורים בכלל
ואני באמת לא..
 

vinney

Well-known member
אלדד אמר בדיוק את מה שאני אמרתי

אין שום הבדל התוכנית שהראתי לא תגרום לשגיאת זמן ריצה, היא תגרום לתוצאות בלתי צפויות. אתה לא יכול לדעת מראש אם ערך הזבל זה זכרון ששיך לך או לא, לכן פעם זה יעבוד ופעם יתרסק. לגבי מה שאלדד אמר, אז זה אותו דבר
עכשיו לגבי מחיקה של החוליה ברשימה מקושרת. מה שSTL עושה זה העתק של האובייקט שאתה נותן לו, בעזרת אופרטור =. שים לב, שאם תיצור מחלקה שאין עבורה מימוש של "=" (או אפשרות לבצע השמת ברירת מחדל), תקבל שגיאת קומפילציה. כשאתה מוחק מהרשימה, delete מופעל על ההעתק הזה, לא על האובייקט המקורי. לכן גם ניתן לבצע את זה לטיפוסים בסיסיים- אתה בוודאי יודע שאפשר לעשות new ו delete לint - אתה מקבל מצביע. לגבי הציפיות המוגזמות שלך - אין סיבה שהוא יעדכן את האיטרטור, ברגע שקיבלת את האיטרטור (בזמן שקיבלת אותו הוא היה תקין), זה כבר בעיה שלך שאתה מכשיל אותו, עניין של תכנות תקין.
 

gmorphus

New member
לא ממש

שוב אתה לא מבין מה אנחנו אומרים! תגובות מהסוף להתחלה. קודם כל, אין לי את הציפיות האלה, וכמו שאמרתי גם חסר לו (לSTL) שיעיז לעדכן לי משתנה בלי שביקשתי ממנו - כלומר, אני לא שהוא יעדכן לי את האיטרטור. דבר שני, ברור לי שזה מעין הכשלה של הSTL ולא באמת באג. זה אף פעם לא קרה לי, וזה סתם תהייה. דבר שלישי, לא דיברתי על מצביעים. הרשימה המקושרת ואין קשר אם הוא מעתיק את האובייקט או לא (אני יודע שהוא עושה את זה). אם הוא באמת עושה delete אז אני אמור לקבל זבל וזה באמת מה שקורה. תנסה לעבור על השרשור ולראות איפה לא הבנת אותי. דבר אחרון, נכון שמה שקורה כאן דומה למה שיקרה בתוכנית שלך וזה מה שחשבתי שקורה. פשוט תהיתי אולי לSTL יש איזשהו מנגנון שמגן על מקרים כאלה ומתמודד איתם בצורה כלשהי. כנראה שלא...
 

DadleFish

New member
כדי להתמודד עם הבעיה הזו,

STL הייתה צריכה להיות איטית כמו JAVA, והיא לא - להיפך, היא מכוונת להיות הדבר הכי מהיר שיש, תיאורטית ופרקטית גם יחד
 
למעלה