שאלה ב- ++C

שאלה ב- ++C

בנושא הקצאות דינמיות וסטטיות: בתכנית שכתבתי, אני אמורה להחזיק המון טבלאות נתונים (בזיכרון) לצרוך חישובים. הטבלה מוגדרת כוקטור של פוינטרים למבנה מסוים, שהוא מחלקה אבסטרקטית. נקרא לה A. B ו- C הן 2 מחלקות היורשות מ- A, כך שבפועל הפונקציה בונה טבלה שהיא וקטור של B-ים או וקטור של C-ים. כרגע ההקצאה היא דינמית והיא מבוצעת בנפרד עבור כל שורה בטבלה. הבעיה היא שבגלל גודל הטבלאות ומספרן, ההקצאה הדינמית המפוצלת מאוד מאטה את התכנית וגורמת לה להיות לא יעילה. כיצד אני יכולה לייעל את התכנית? האם ניתן להקצות את כל הטבלה בבת אחת? (אני יודעת מה הגודל המקסימלי שלה) הרי גם אם אני מקצה את הוקטור של הפוינטרים מראש, את השורות בטבלה אני לא רואה איך אני יכולה להקצות בפעם אחת (אלא אם כן הטבלה היא של A ולא של פוינטר ל-A, אבל זה לא אפשרי, כי A הוא מחלקה אבסטרקטית..
).. נראה לי שלא הסברתי את עצמי כל כך טוב... מקווה שהבנתם. תודה, שרון.
 

vinney

Well-known member
לא ברור כל כך

כשאת עובדת עם מחלקות, את לא יכולה מראש להקצות מקום ל20 אובייקטים, את חייבת לעשות new לכל אובייקט בנפרד. אני מקווה גם שאת משתמשת ב vector של STL, ולא ממשת את ניהול הוקטורים לבד. חוצמזה, לא ברור לי כל כך איפה אפשר לעשות אופטימיזציות לקוד שלך, הרבה יותר קל יהיה לראות את הקוד.
 
זאת בדיוק הבעיה...

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

vinney

Well-known member
לא, אי אפשר

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

annefan

New member
יש דרך, אבל לא טריוויאלית

בהנחה שאת יודעת את הגודל של הטבלאות שלך (לא חייב להיות מדויק, אבל רצוי מאוד לדייק ככל האפשר), את יכול לעבוד עם memory-pool. בגדול, תבצעי הקצאת זיכרון אחת גדולה לכל הנתונים ממערכת ההפעלה, ואח"כ מתוך הזכרון שקיבלת, תקצי זכרון לכל אוביקט משלך. יותר מזה, את יכולה לחפוף את operator new, כך שהקוד שצורך את הזכרון לא ישתנה בכלל. חפשי בגוגל לפי המילים: c++ "memory pool" operator new לא טריויאלי, אבל יכול לשפר מאוד את הביצועים שלך.
 

vinney

Well-known member
אני הייתי עושה משהו אחר לגמרי

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

cybordyn

New member
אפשר להקצות מראש את כל הטבלה.

בגלל הטיפוס של A את לא יכולה להקצות אובייקטים מסוגו אבל את כן יכולה להקצות אובייקטים מסוג B ו C. מה שברור הוא, שברגע ההקצאה את יודעת איזה סוג של אובייקט את צריכה (B או C). לכן, מה שאני מציע: נניח שהטבלה שלך בת M שורות ו N עמודות. אז בזמן ההקצאה את מקצה N x M אובייקטים מסוג B או C, את כאמור יודעת איזה את צריכה. אחרי שהקצת והחזרת את הפווינטר שהוא מטיפוס class *a, את יכולה לעבוד ישירות על הטבלה. למשל על מנת לגשת לאיבר בשורה ה m והעמודה ה n נבצע: table_ptr[(m * N)+n] = value אבל, אם הבעיה שהגודל של טיפוס הנתונים B,C הוא שונה ואת חוששת שהחישוב של הפויינטר לא ייצא נכון (ויתקנו אותי חכמי-הפורום, לפי מה מתבצע חישוב-הפוינטר של טיפוס אבסטרקטי?). אז יש פתרון יפה גם לזה אפשר להוסיף פונקציה וירטואלית ל A שאח"כ נממש אותה בטיפוסי הנתונים B,C נקרא לפונקציה size_of_item ומה שהיא תחזיר זה את ה sizeof של B ו C בהתאמה. עכשיו את יכולה לבצע את החישוב של הפוינטר: char *temp_table_ptr = table_ptr class A *current_item temp_table_ptr += ((m * N)+n) * table_ptr[0].size_of_item() currnet_item = temp_table_ptr תזכרי ש size_of_item תמיד יחזיר את הגודל לטיפוס הנכון כי הפונקציה היא וירטואלית, למרות שהגישה היא דרך class *A. שימי לב למתווך של char *temp_table_ptr צריך כאן פוינטר ל char כדי שהחישוב יצא נכון. בהצלחה!
 
למעלה