איך להקצות מערך ללא אתחול בC++ - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

איך להקצות מערך ללא אתחול בC++


djdodo

Recommended Posts

  • 1 חודש מאוחר יותר...

Boomerang , התשובה שלך לא נכונה בכלל.

מה קורה כאשר אתה מקבל מחלקה ממישהו אחר שכתב אותה ואין לך שליטה על ה- CONSTRUCTORS שלה???

יש מקבילה אמיתית ל-MALLOC ו-DEALLOC- ב-C++ , קוראים לזה PLACEMENT OPERATOR NEW ו- PLACEMENT OPERATOR DELETE.

להלן קישור המסביר על אופרטרים אלו:

http://www.glenmccl.com/tip_025.htm

בכל מקרה אחי , NO OFFENCE , לא משהו אישי נגדך פשוט היה חשוב לי להגיד את הדבר הנכון.

קישור לתוכן
שתף באתרים אחרים

מה קורה כאשר אתה מקבל מחלקה ממישהו אחר שכתב אותה ואין לך שליטה על ה- CONSTRUCTORS שלה???

עדיין, אם לא תאתחל את המשתנים שלך, הם לא יאותחלו.

ה- placement new בהחלט חדש לי (ואני כותב C++ כבר 12 שנה).

ממה שאני רואה זה לא מקבילה ל- malloc אלא סוג של overload+override לאופרטור new והוא עדיין קורא ל- constructor כשהוא מסיים.

קישור לתוכן
שתף באתרים אחרים

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

אתה צודק , PLACEMENT NEW הוא לא מקביל לMALLOC , מה שכן , ניתן להשתמש בו בשביל לקרוא לבנות אובייקט מסוים על שהוקצה מראש וככה למעשה פועלים הCONTAINERS של STL.

NEW הרגיל מבצע שני דברים:

1. מבקש ממערכת ההפעלה בגודל הדרוש.

2. מאתחל אובייקט(ים) על הזכרון הזה.

באמצעות OVERRIDE ספציפי של PLACEMENT NEW ניתן ל"דלג" על השלב הראשון ולבצע רק את החלק השני.

לגבי השלב הראשון , אפשר להקצות מבלי לאתחל שום אובייקט באמצעות קריאה לOPERATOR NEW של הGLOBAL SCOPE.

היתרון בפירוק הזה הוא שהרבה פעמים הוא מאפשר לך לעשות שיפור בביצועים.

ניקח לדוגמה את ה-VECTOR של STL , נניח ומקצים VECTOR של 10 איברים מסוג של מחלקה A.

מצד אחד אין שום הגיון בכך שבCOSTRUCTOR של הVECTOR כבר יאתחל מיידית את עשרת האובייקטים (לא נראה לי שצריך להסביר למה).

מצד שני הCONSTRUCTOR כן צריך לשריין לעצמו את כל הזכרון הדרוש מראש.

אז מה שקורה בפועל בהרבה מימושים של ה-STL זה שהזכרון בלבד מוקצה בCONSTRUCTOR , בעוד שהאתחולים של האובייקטים שהVECTOR "מכיל" מתבצעים רק בשעת הצורך בזמן העבודה עם הVECTOR והאתחולים הללו יבוצעו באמצעות PLACEMENT NEW.

לגבי התגובה שלך:

קודם כל , ברגע שאתה מאתחל מחלקה A כלשהי , אוטומטית תרצה או לא תרצה , כל החברים (אלו שלאPRIMITIVE ) במחלקה הזו מאותחלים.

כל חבר יאותחל באחת מהדרכים הבאות:

1או שהגדרת אתחול כלשהו בבנאי של A עבור אותו חבר , ואז יקרא הבנאי המתאים של אותו חבר.

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

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

דבר שני , גם אם זה היה נכון מה שאתה אומר , תחשוב על הסיטואציה הבאה:

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

אבל עזוב חבר לצוות , קנית קוד מאיזה חברה אחרת , אתה באמת רוצה להתעסק עם הקוד הזה?

קישור לתוכן
שתף באתרים אחרים

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

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

קישור לתוכן
שתף באתרים אחרים

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

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

אוקיי סבבה , הבנתי , אבל לצורך העניין , עדיין (אם אני מבין נכון ;) ),הפתרון שאתה מציע הוא פשוט לא נכון מכמה סיבות:

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

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

3. ייתכן ובמחלקה יש MEMBER שהוא גם מחלקה , במקרה הזה יקרא בנאי כלשהו של הMEMBER הזה תרצה או לא תרצה ואז ייתכן מאוד שכבר לא הכל יהיה ערך זבל.

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

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

בקיצור , אני יכול לחשוב על עוד סיבות אבל הבאתי מספיק.

הפתרון הנכון הוא להשתמש בOPERATOR NEW של הGLOBAL SCOPE או לחלופין אפשר גם לעשות NEW של CHAR* ואז לעשות בCASTING לVOID* (ממליץ יותר על הראשון).

בשביל לבנות אובייקט מאוחר יותר על שטח הזכרון הזה , ניתן להשתמש ב-PLACEMENT NEW

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

קישור לתוכן
שתף באתרים אחרים

הפיתרון שהצעתי מוגבל למשתנים פרימיטיביים שמוגדרים ב- class עצמו. ההגבלה כאן שהמשתנים האלה יהיו private אפילו יותר חמורה מבדר"כ.

ה- constructor של ה- members וה- parent-class ייקראו, אבל הם ייקראו גם בכל מימוש של new או של placement new.

אם אני מבין נכון, כל מה שהפיתרון עם placement new מאפשר לך זה להקצות את הזיכרון מראש. אפשר אולי להשתמש בזה לדברים קצת יותר מעניינים (כמו להקצות קצת יותר ולשמור בזיכרון הנוסף עוד משהו מחוץ ל- class) אבל לא נראה לי שזה מקדם אותנו בכיוון.

c++ לא מאפשרת לך "רק להקצות זיכרון" כי אז מה שתקבל זה לא אובייקט אלא סתם חתיכת (אם ה- vptr לא ייתאתחל בכלל יהיה לך בלאגן בכל מה שנוגע לפונקציות וירטואליות). אם אתה ממש רוצה לעשות את זה - אתה תמיד יכול לעשות malloc לגודל של האובייקט ו- casting ל- class שלך.

קישור לתוכן
שתף באתרים אחרים

C++ בהחלט מאפשרת לך להקצות בלבד בלי שום קשר לאובייקט כלשהו.

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

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

מה שטוב בזה זה שיש לך עכשיו שליטה על התהליך הרגיל שקורה בNEW , אתה יכול להחליט מתי יתבצע כל אחד מהשלבים של NEW.

קישור לתוכן
שתף באתרים אחרים

Yossi1981 צודק.

Placement new הוא הפתרון המקובל ב-C++ כאשר רוצים להקצות ללא אתחול מחלקה אובייקט. יש מספר טכניקות (חלק מהן אפילו ממש hacks אבל לא משנה) המשתמשות בזה.

ולצורך שלמות: כן, אפשר לקרוא ל-destructor באופן ישיר ללא שחרור הזכרון, ואפילו לdtor וירטואלי.

קישור לתוכן
שתף באתרים אחרים

אבל השאלה המקורית היתה:

איך אני מקצה מערך בC++ בעזרת NEW ככה שבכל התאים יהיה זבל ושכל התאים לא יאותחלו לערך כלשהו.

בדיוק כמו שהפונקציה malloc עושה בC

נכון שהשאלה לא מוגדרת כ"כ טוב, אבל בסופו של דבר כל new יגרור הפעלה של constructor. עם זה אתם מסכימים?

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

×
  • צור חדש...