כותב |
|
דניאל ל. אורח
הצטרף / הצטרפה: 01 October 2003
משתמש: אונליין הודעות: 12647
|
נשלח בתאריך: 19 August 2006 בשעה 12:45 | | IP רשוּם
|
|
|
|
הורדתי את המדריך הקצר שמפורסם פה באתר על smart pointers, ונתקלתי בקטע קוד שאני מתלבט אם הוא בעייתי או שאולי אני טועה. להלן קטע הקוד:
קוד:
#include <iostream> #include <memory> using namespace std; int main() { auto_ptr<int> p; int i = 7; p.reset(&i); cout << "The pointer points to: " << *p << endl; *p = 10; cout << "Contents of i: " << i << endl; return 0; }
|
|
|
אולי לא הבנתי נכון אבל לפי מה שמוסבר שם בסוף הפונקציה בקריאה ל-destructor של p תהיה קריאה ל-delete עם הכתובת של i, ו- i לא הוקצה ע"י new (שזה אמור להיות בעייתי עד כמה שידוע לי).
|
חזרה לתחילת העמוד |
|
|
ReX :D אורח
הצטרף / הצטרפה: 01 October 2003
משתמש: אונליין הודעות: 12647
|
נשלח בתאריך: 19 August 2006 בשעה 17:07 | | IP רשוּם
|
|
|
|
הכוונה היא שתיהיה קריאה לdestructor והזיכרון של המצביע p ישוחרר.
|
חזרה לתחילת העמוד |
|
|
דניאל ל. אורח
הצטרף / הצטרפה: 01 October 2003
משתמש: אונליין הודעות: 12647
|
נשלח בתאריך: 19 August 2006 בשעה 20:36 | | IP רשוּם
|
|
|
|
אבל ה-Destructor של auto_ptr עושה delete למצביע שהוא מכיל...
|
חזרה לתחילת העמוד |
|
|
אורח אורח
הצטרף / הצטרפה: 01 October 2003
משתמש: אונליין הודעות: 12647
|
נשלח בתאריך: 19 August 2006 בשעה 20:47 | | IP רשוּם
|
|
|
|
נו בסדר הוא מוחק את p ולא את i.
|
חזרה לתחילת העמוד |
|
|
אלצ'קו אחראי פורומים
ג2ר פ33תי
הצטרף / הצטרפה: 20 January 2006
משתמש: מנותק/ת הודעות: 609
|
נשלח בתאריך: 20 August 2006 בשעה 02:21 | | IP רשוּם
|
|
|
|
על פניו נראה שאתה צודק.
ReX :D כתב:
הכוונה היא שתיהיה קריאה לdestructor והזיכרון של המצביע p ישוחרר.
|
|
|
כן. והמפרק של ה-auto_ptr ינסה לעשות delete למצביע שהוא שומר אצלו. אלא
שהמצביע הוא למשתנה שנמצא במחסנית ולא על הערימה. נחש למה זה אמור לגרום...
|
חזרה לתחילת העמוד |
|
|
aassaa1 משתמש מתחיל
הצטרף / הצטרפה: 24 August 2006 מדינה: Israel
משתמש: מנותק/ת הודעות: 6
|
נשלח בתאריך: 24 August 2006 בשעה 15:54 | | IP רשוּם
|
|
|
|
אם כתבו את הSMART POINERS כמו שצריך זה לא ימחק משהו שלא הוקצה
|
חזרה לתחילת העמוד |
|
|
אלצ'קו אחראי פורומים
ג2ר פ33תי
הצטרף / הצטרפה: 20 January 2006
משתמש: מנותק/ת הודעות: 609
|
נשלח בתאריך: 24 August 2006 בשעה 22:10 | | IP רשוּם
|
|
|
|
aassaa1 כתב:
אם כתבו את הSMART POINERS כמו שצריך זה לא ימחק משהו שלא הוקצה |
|
|
אתה מוכן לספק לנו מימוש של auto_ptr שיודע לגלות בשיטת קסמים תקנית האם
המצביע שקיבל נוצר בעזרת delete או בעזרת הצהרה סטטית? כמובן שלא, כי זה
בלתי אפשרי.
קרא את זה. אולי תלמד משהו.
|
חזרה לתחילת העמוד |
|
|
aassaa1 משתמש מתחיל
הצטרף / הצטרפה: 24 August 2006 מדינה: Israel
משתמש: מנותק/ת הודעות: 6
|
נשלח בתאריך: 25 August 2006 בשעה 18:01 | | IP רשוּם
|
|
|
|
template<class T> auto_ptr {
T* ptr
//...
bool DidNew
//...
auto_ptr::~auto_ptr(){
if (DidNew) delete[] ptr
}
|
חזרה לתחילת העמוד |
|
|
אלצ'קו אחראי פורומים
ג2ר פ33תי
הצטרף / הצטרפה: 20 January 2006
משתמש: מנותק/ת הודעות: 609
|
נשלח בתאריך: 25 August 2006 בשעה 18:20 | | IP רשוּם
|
|
|
|
חכם בלילה, אה?
ואיך יקבע ערכו של DidNew? ומה פתאום החלטת שמשתמשים ב-delete[] ולא
ב-delete? אחלה קוד, שברגע שאשתמש בו במקום במימוש ש-MS מביאים לי, לאחר
קימפול מחדש, כל הקודים שלי יפסיקו לפעול, כי ה-auto_ptr הגאוני שלך מנסה
לעשות delete[] למה שהושג בעזרת new...
|
חזרה לתחילת העמוד |
|
|
אורח אורח
הצטרף / הצטרפה: 01 October 2003
משתמש: אונליין הודעות: 12647
|
נשלח בתאריך: 27 August 2006 בשעה 05:43 | | IP רשוּם
|
|
|
|
אלצ'קו כתב:
על פניו נראה שאתה צודק.
ReX :D כתב:
הכוונה היא שתיהיה קריאה לdestructor והזיכרון של המצביע p ישוחרר.
|
|
|
כן. והמפרק של ה-auto_ptr ינסה לעשות delete למצביע שהוא שומר אצלו. אלא
שהמצביע הוא למשתנה שנמצא במחסנית ולא על הערימה. נחש למה זה אמור לגרום...
|
|
|
למה זה יגרום? וזה באמת מנסה למחוק את ה i? אם כן, אז ה smart pointers לא ממש חכמים :
|
חזרה לתחילת העמוד |
|
|
aassaa1 משתמש מתחיל
הצטרף / הצטרפה: 24 August 2006 מדינה: Israel
משתמש: מנותק/ת הודעות: 6
|
נשלח בתאריך: 27 August 2006 בשעה 10:19 | | IP רשוּם
|
|
|
|
אלצ'קו כתב:
חכם בלילה, אה?
ואיך יקבע ערכו של DidNew? ומה פתאום החלטת שמשתמשים ב-delete[] ולא ב-delete? אחלה קוד, שברגע שאשתמש בו במקום במימוש ש-MS מביאים לי, לאחר קימפול מחדש, כל הקודים שלי יפסיקו לפעול, כי ה-auto_ptr הגאוני שלך מנסה לעשות delete[] למה שהושג בעזרת new...
|
|
|
בטח יש דרך יותר טובה לעשות את זה אבל הדרך הכי פשוטה קודם לענין השני שלך זה
bool isArray
לשאלה הראשונה אפשר להעמיס את האופרטור new כך שיקבע את ערכו של DidNew
קוד:
template <class T>
void *operator new(size_t size);
|
|
|
ואת האופרטור new[] כך שיקבע גם את ערכו של isArray
|
חזרה לתחילת העמוד |
|
|
אלצ'קו אחראי פורומים
ג2ר פ33תי
הצטרף / הצטרפה: 20 January 2006
משתמש: מנותק/ת הודעות: 609
|
נשלח בתאריך: 27 August 2006 בשעה 11:11 | | IP רשוּם
|
|
|
|
אורח כתב:
למה זה יגרום? וזה באמת מנסה למחוק את ה i? אם כן, אז ה smart pointers לא ממש חכמים : |
|
|
זה באמת באמת ינסה למחוק את ה-i. למה שלא ינסה? בקוד של auto_ptr בודקים
האם יש לו ownership על המצביע, ואם כן הוא מבצע עליו delete במפרק, או
בהעברת בעלות, או אם "מחברים" אליו מצביע חדש.
למה זה יגרום? התוצאות של שימוש ב-delete על מצביע שלא הושג באמצעות new
אינן מוגדרות. זה אומר שהפעולה הזו יכולה לעשות כל דבר, בין קריסה מיידית,
קריסה בעתיד ברגע לא קשור, או הפקה של תוצאות בלתי-צפויות. בעצם, המשמעות
של "תוצאה בלתי מוגדרת" היא שהדבר היחיד שכנראה לא יקרה, הוא מה שאתה מצפה
שיקרה. כל השאר, כולל הכחדה של כל פרות משה רבנו בעולם,הוא אפשרות.
|
חזרה לתחילת העמוד |
|
|
אלצ'קו אחראי פורומים
ג2ר פ33תי
הצטרף / הצטרפה: 20 January 2006
משתמש: מנותק/ת הודעות: 609
|
נשלח בתאריך: 27 August 2006 בשעה 11:14 | | IP רשוּם
|
|
|
|
aassaa1 כתב:
אלצ'קו כתב:
חכם בלילה, אה?
ואיך יקבע ערכו
של DidNew? ומה פתאום החלטת שמשתמשים ב-delete[] ולא ב-delete? אחלה קוד,
שברגע שאשתמש בו במקום במימוש ש-MS מביאים לי, לאחר קימפול מחדש, כל
הקודים שלי יפסיקו לפעול, כי ה-auto_ptr הגאוני שלך מנסה לעשות delete[]
למה שהושג בעזרת new...
|
|
|
בטח יש דרך יותר טובה לעשות את זה אבל הדרך הכי פשוטה קודם לענין השני שלך זה
bool isArray
לשאלה הראשונה אפשר להעמיס את האופרטור new כך שיקבע את ערכו של DidNew
קוד:
template <class T>
void *operator new(size_t size);
|
|
|
ואת האופרטור new[] כך שיקבע גם את ערכו של isArray |
|
|
אתה פשוט מביך את עצמך. זה שאתה "בטוח שיש דרך לעשות את זה" לא אומר שהיא
קיימת. בעצם, ידוע שהיא לא קיימת. זה פשוט בלתי-אפשרי ללא שינוי הממשק של
auto_ptr.
זה נחמד שיש לך bool isArray, אבל אין לך דרך לקבוע את הערך שלו, בדיוק
כמו שאין לך דרך לקבוע את הערך של DidNew. הניסיון החביב שלך לפתור את זה
ע"י העמסת new הוא way of course. הרי auto_ptr בכלל לא משתמש ב-new,
ואובייקטים מטיפוס auto_ptr אמורים להיות מוקצים סטטית. ה-new נעשה על
הטיפוס שמשתנה שלו ה-auto_ptr מחזיק.
בקיצור, במקום לבלבל את המוח, תן דוגמה למימוש שלם (יעני אחשלי, קוד שאני
יכול לקמפל, ויהווה תחליף שלם ל-auto_ptr שיש לי כרגע) שיודע לזהות מערכים
ומצביעים שלא הושגו בעזרת new...
|
חזרה לתחילת העמוד |
|
|
aassaa1 משתמש מתחיל
הצטרף / הצטרפה: 24 August 2006 מדינה: Israel
משתמש: מנותק/ת הודעות: 6
|
נשלח בתאריך: 27 August 2006 בשעה 12:21 | | IP רשוּם
|
|
|
|
תקרא את המדריך ההוא עוד פעם תראה שכל מה שאמרתה כרגע לא נכון אם תחשוב קצת תראה שהמימוש שלו ממש קל
|
חזרה לתחילת העמוד |
|
|
אלצ'קו אחראי פורומים
ג2ר פ33תי
הצטרף / הצטרפה: 20 January 2006
משתמש: מנותק/ת הודעות: 609
|
נשלח בתאריך: 27 August 2006 בשעה 12:59 | | IP רשוּם
|
|
|
|
לסיכום, לא הבנת מילה ממה שהרב כתב, וטענת פעם אחר פעם 3 שטויות ענקיות:
- auto_ptr לא ינסה לעשות delete למצביע שלא נוצר בעזרת new. (הוא ינסה ועוד איך)
- יש דרך ב-CPP תקני לגלות האם הזיכרון שאליו מצביע מצביע הוקצה סטטית או בעזרת new. (בלתי אפשרי, שלא להזכיר את זה שאת m/calloc שכחת)
- יש דרך לגלות האם מצביע הושגה באמצעות new או באמצעות new[] (כנ"ל. בלתי אפשרי לחלוטין)
והכי טוב: כתבת שהמימוש של שלושת הדברים הבלתי אפשריים האלה הוא "ממש קל".
ועכשיו סיכום עבורך: שמור את השטויות האלה לעצמך. אתה לא מסוגל להודות בטעות, לא נורא. בעיה שלך. אל תחלק לאנשים "טיפים" שגויים.
|
חזרה לתחילת העמוד |
|
|