ABA


"להבין C++ - טיפ/חידה(?) #1"
גירסת הדפסה        
קבוצות דיון פיתוח, תיכנות ובניית אתרים נושא #15952 מנהל    סגן המנהל    מפקח   Winner    צל"ש   מומחה  
אשכול מספר 15952
Sn00py 
חבר מתאריך 1.8.02
2954 הודעות
   13:28   18.06.10   
אל הפורום  
  להבין C++ - טיפ/חידה(?) #1  
 
   שלום שלום פורום נכבד
במהלך השירות שלי יוצא לי לדבר עם מתכנתים מכל מני מקומות, בוגרי קורסים שונים.
שמתי לב לתופעה מוזרה במיוחד. האנשים האלו ידעו לדקלם לכם מה היא הורשה, למה צריך פולימורפיזם ובכלל למה נורא חשוב לשמור על thread safety ושאר דברים. זה בהחלט יפה מאוד.
אותם אנשים, הרבה מהפעמים, מתפסטנים ימים שלמים על דיבוג בעיות, או יותר גרוע - יוצרים בעיות שאנשים אחרים יצטרכו לדבג אחר כך..
הסיבה היא לא טיפשות, היא פשוט חוסר הבנה של שפות מסוימות.

אחרי ההקדמה הנ"ל - החלטתי לתת מדי פעם(אני אשתדל כל שבוע, ואולי גם יותר - בהתאם להיענות) טיפים לגבי טעויות שאני רואה שמתכנתים עושים לפעמים, בעיקר מתכנתים צעירים/לא מתורגלים ב-CPP.

אני אתחיל מדברים טריוואלים יחסית, ואני אשתדל לגעת בכל מני אספקטים של OOP/ C++. בהמשך אני אולי אכנס לדברים שיכולים לשגע את השכל עם WIN API וכו'. הכל בהתאם להאם זה יעניין את אנשי הפורום.

ואחרי החפירה - בואו נתחיל.

כמה דברים:
1. בבקשה, לכתוב תשובות בתוך התוכן ולא בכותרת - כדי לא להרוס לאנשים שרוצים לחשוב גם הם.

2. ברור לי שהקוד נראה על הפנים. זאת לא המטרה מן הסתם.

והיום - מה לא בסדר בקוד הנ"ל? (בלי לקמפל, בלי להריץ!)
לצורך העניין, canUnloadNow היא מתודה סטטית של Helper, שקובעת האם מותר לנו למחוק את העצמים/לעשות הריסה כלשהי של התכנית.. זה לא חשוב


#include <iostream>
#include <windows.h>

using std::exception;

#define TRACE(x) OutputDebugStringA(x)


class A {
public:
A() {
TRACE("A Ctor\n");
}
~A() {
if (!Helper::canUnloadNow()) {
TRACE("A: Cannot unload now!\n");
throw std::exception();
}
}
};


class B {
public:
B() { TRACE("B Ctor\n"); }
~B() {
if (!Helper::canUnloadNow()) {
TRACE("B: Cannot unload now!\n");
throw std::exception();
}
}
private:
A a;
};


int main ()
{
try {
B a;
}
catch (...) {
TRACE("Exception!\n");
}
}

\x6C\x65\x65\x74\x68\x61\x78\x30
\x72\x3A\x2D\x29
tresp4sser


                                שתף        
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

  האשכול     מחבר     תאריך כתיבה     מספר  
  אחלה חידה :) אני אשאיר לאנשים אחרים לענות עליה Net_Boy  18.06.10 17:18 1
  ניסיון shay86  19.06.10 12:42 2
     לא מה שהתכוונתי, למרות ששני הדברים שכתבת נכונים Sn00py  19.06.10 15:04 3
         הבנתי אותך shay86  19.06.10 15:36 4
             נכון שנעוף Sn00py  19.06.10 16:12 5
                 ניסיתי עכשיו להריץ את הקוד אצלי shay86  19.06.10 16:21 6
                     בוא ננסה להבין איפה אתה עף Sn00py  19.06.10 17:57 8
  רמז : תחשבו איך ה STACK מתנהג בזמן EXCPETION Net_Boy  19.06.10 16:28 7
  תשובה + כלל אצבע Sn00py  19.06.10 19:51 9
     יפה מאוד, השכלתי :) ronen333  19.06.10 20:58 10
     יפה, תודה רבה :) shay86  19.06.10 21:03 11
     השכלתי, ידעתי שאסור (!) לזרוק אקספשיין בD'tor אבל אף פע פאביו ג'וניור 20.06.10 02:04 12

       
Net_Boy  לחץ כאן להצגת דירוג המשתמש
חבר מתאריך 1.4.02
17151 הודעות, 1 פידבק
   17:18   18.06.10   
אל הפורום  
  1. אחלה חידה :) אני אשאיר לאנשים אחרים לענות עליה  
בתגובה להודעה מספר 0
 
  


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
shay86 
חבר מתאריך 13.5.06
197 הודעות
   12:42   19.06.10   
אל הפורום  
  2. ניסיון  
בתגובה להודעה מספר 0
 
   1. אין ערך חזרה ל- main..
2. אני לא בטוח לגבי זה, אבל לדעתי כשנכנסים ל- DTOR אז אי אפשר לעצור כבר את פעולת הריסת האובייקט, ולכן הקריאה לפונקציה הסטטית לא רלוונטית.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Sn00py 
חבר מתאריך 1.8.02
2954 הודעות
   15:04   19.06.10   
אל הפורום  
  3. לא מה שהתכוונתי, למרות ששני הדברים שכתבת נכונים  
בתגובה להודעה מספר 2
 
   1. אין ערך חזרה ל MAIN - צודק, אבל זה לא ימנע מקימפול וגם לא יקריס את התוכנית. הכל יעבוד. הקומפיילר יוסיף return 0 בסוף לבד(VC9).

2. אתה גם צודק. הכוונה שלי: עשיתי משהו בתוכנית למעלה שיגרום לתוכנית להדפק ממש. ב100 אחוז מהפעמים. נניח שמה שאני רוצה לבדוק באמצעות הפונקציה הסטטית זה האם לכתוב הודעה ללוג או לא. את זה אני יכול להחליט כמובן באמצעות ה IF שכתבתי. השאלה שלי: האם זה יעבוד, האם לא - ובעיקר למה.

היום בערב אני אכתוב תשובה אם לא יתנו אחת.

\x6C\x65\x65\x74\x68\x61\x78\x30
\x72\x3A\x2D\x29
tresp4sser


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
shay86 
חבר מתאריך 13.5.06
197 הודעות
   15:36   19.06.10   
אל הפורום  
  4. הבנתי אותך  
בתגובה להודעה מספר 3
 
   כיוון ש- A מוגדר בתוך B (כ- VALUE) אזי ה- DTOR שלו יקרא אוטומטית כש- B נהרס,
כיוון שנזרק EXCEPTION מתוך ה- DTOR של B אז אי אפשר להגיע ל- DTOR של A ונעוף.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Sn00py 
חבר מתאריך 1.8.02
2954 הודעות
   16:12   19.06.10   
אל הפורום  
  5. נכון שנעוף  
בתגובה להודעה מספר 4
 
   אבל זה לא שאי אפשר להגיע - אני הרי עושה TRY.. CATCH.
אנחנו נגיע לDTOR של A ואז נעוף.
השאלה היא למה

\x6C\x65\x65\x74\x68\x61\x78\x30
\x72\x3A\x2D\x29
tresp4sser


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
shay86 
חבר מתאריך 13.5.06
197 הודעות
   16:21   19.06.10   
אל הפורום  
  6. ניסיתי עכשיו להריץ את הקוד אצלי  
בתגובה להודעה מספר 5
 
   ואני עף עוד ב- DTOR של B (לא הגעתי בכלל ל- DTOR של A).


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Sn00py 
חבר מתאריך 1.8.02
2954 הודעות
   17:57   19.06.10   
אל הפורום  
  8. בוא ננסה להבין איפה אתה עף  
בתגובה להודעה מספר 6
 
   אתה עף ב throw אני מניח.
מה קורה שאתה עושה throw? הruntime שלך יחפש את ה exception handler הקרוב. זאת אומרת שהוא יצא מהדיסטרקטור שלך(של B). מה הדיסטורקטור(B) שלך עוד לא עשה? לא הרג את כל ה automatic objects שלך - ש A בינהם(כי הוא מוגדר כ member של המחלקה, על הסטאק). זאת אומרת, ברגע שקרה ה- THROW, ה runtime כן קרא ל DTOR של A.

אם תשים BREAKPOINTS גם ב DTOR של A וגם ב DTOR של B, אתה תראה שהוא מגיע לשניהם - ואתה עף מהתוכנית שלך רק ב THROW של A

\x6C\x65\x65\x74\x68\x61\x78\x30
\x72\x3A\x2D\x29
tresp4sser


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Net_Boy  לחץ כאן להצגת דירוג המשתמש
חבר מתאריך 1.4.02
17151 הודעות, 1 פידבק
   16:28   19.06.10   
אל הפורום  
  7. רמז : תחשבו איך ה STACK מתנהג בזמן EXCPETION  
בתגובה להודעה מספר 0
 
  


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Sn00py 
חבר מתאריך 1.8.02
2954 הודעות
   19:51   19.06.10   
אל הפורום  
  9. תשובה + כלל אצבע  
בתגובה להודעה מספר 0
 
   נתחיל מכלל האצבע
לעולם, לעולם, לעולם(!) אין לזרוק Excpetions מ Destructor

ולמה?

כאשר נזרק excpetion, מתבצע תהליך של stack unwinding. מה זאת אומרת? הסטאק מתחיל להתנקות מכל האובייקטים שהוקצו עליו,
החל מהנקודה שעשינו throw X ועד הנקודה שעשינו catch X(או במקרה שאין catch, עד ה default exception handler שמוגדר על ידי ה runtime).

אם במהלך אחד מה-DTORים האלה נזרק אקספשן נוסף -
ה runtime של C++ יקרא אוטומטית לפונקציה terminate() ויסיים את ריצת התוכנית!

למה זה הגיוני? נניח שיש לנו DTOR אחד שזורק LiranException. אחרי שה-Exception נזרק,
מתחיל תהליך הנקיון של הסטאק(unwinding) שבמהלכו נקרא ה destructor של אובייקט כלשהו שהיה לנו במחלקה.
האובייקט הזה, בתורו, זורק גם הוא אקספשן ב destructor, מסוג OmerException.מה עושים עכשיו? עד לאן צריך לעשות unwinding?
עד catch(OmerException&)? עד catch(LiranException&)?

התקן של C++ החליט שבכל מצב, אנחנו נפסיד פה משהו.
הרי אי אפשר ללכת לשניהם, כי אי אפשר להחזיק שני EXCEPTIONים ברגע נתון (אבל על זה, בפעם אחרת).

אמנם, אפשר לומר "אז בעצם, אם מובטח שרק אובייקט אחד בכל רגע נתון זורק
excpetion ב- DTOR, אז הכל בסדר"

נכון. אבל עדיין, בחיים לא עושים את זה. כי מתכנתים אחרים יכולים לא
לדעת את זה. ומעבר לזה - זה ממש ממש מכוער.

אז הכלל הוא:
לעולם, לעולם, לעולם(!) אין לזרוק Excpetions מ Destructor

אז תשאלו: "רגע, לירן, אז מתי כן אפשר לזרוק excpetionים ב desutrctor?"
והתשובה היא: אף פעם

"בלי חריגות?"
בלי! לעולם, לעולם, לעולם(!) אין לזרוק Excpetions מ Destructor

אני מקווה שהבהרתי את הכוונה שלי

אם יש שאלות - אשמח לענות.

מקווה שנהניתם - עד הפעם הבאה.
לירן

\x6C\x65\x65\x74\x68\x61\x78\x30
\x72\x3A\x2D\x29
tresp4sser


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ronen333 
חבר מתאריך 20.2.03
6069 הודעות
   20:58   19.06.10   
אל הפורום  
  10. יפה מאוד, השכלתי :)  
בתגובה להודעה מספר 9
 
   אם כי אף פעם לא עשיתי את זה.. עכשיו אני יודע גם שבעתיד בחיים לא אעשה את זה .


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
shay86 
חבר מתאריך 13.5.06
197 הודעות
   21:03   19.06.10   
אל הפורום  
  11. יפה, תודה רבה :)  
בתגובה להודעה מספר 9
 
  


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
פאביו ג'וניור

   02:04   20.06.10   
אל הפורום  
  12. השכלתי, ידעתי שאסור (!) לזרוק אקספשיין בD'tor אבל אף פע  
בתגובה להודעה מספר 9
 
   אבל אף פעם לא ידעתי למה


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

תגובה מהירה  למכתב מספר: 
 
___________________________________________________________________

___________________________________________________________________
למנהלים:  נעל | תייק בארכיון | מחק | העבר לפורום אחר | מחק תגובות | עגן אשכול
       



© כל הזכויות שמורות ל-רוטר.נט בע"מ rotter.net