זיכרון דינמי (new/delete)
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 14 מתוך 104.
עכשיו, אחרי שהבנת מצביעים והפניות, בוא נשתמש בהם כדי לבצע הקצאת זיכרון דינמית. האופרטורים new ו־delete מאפשרים לך ליצור ולהשמיד אובייקטים בערימה בזמן ריצה.
השתמשו ב-new כדי להקצות זיכרון ולקבל מצביע אליו:
int* num = new int; // הקצה מספר שלם יחיד
*num = 42; // הצב ערך באמצעות מצביע
Player* player = new Player("Hero"); // הקצה אובייקטלכל new חייב להיות delete תואם כדי לשחרר את הזיכרון:
delete num; // משחרר אובייקט יחיד
delete player; // קורא ל-destructor, ואז משחרר את הזיכרוןעבור מערכים, השתמשו ב־new[] וב־delete[]:
int* scores = new int[5]; // הקצה מערך של 5 מספרים שלמים
scores[0] = 100;
delete[] scores; // שחרר את המערך - שים לב לסוגריים המרובעים!טעויות נפוצות שיש להימנע מהן:
// דליפת זיכרון - שכחנו לבצע delete
int* ptr = new int(10);
ptr = new int(20); // אבדה הגישה להקצאת הזיכרון הראשונה!
// מצביע תלוי - שימוש לאחר delete
delete ptr;
*ptr = 5; // התנהגות לא מוגדרת!
// שימוש ב-delete לא תואם
int* arr = new int[10];
delete arr; // שגוי! צריך להשתמש ב-delete[]לאחר המחיקה, הגדירו את המצביעים ל־nullptr כדי להימנע משימוש חוזר בשוגג. ניהול זיכרון ידני מועד לשגיאות, ולכן C++ מודרנית מעדיפה מצביעים חכמים, שבהם נעסוק בהמשך.
אתגר
קלבואו נבנה מערכת פשוטה לאחסון הודעות, המדגימה הקצאת זיכרון דינמית באמצעות new ו־delete.
תיצרו שני קבצים כדי לארגן את הקוד:
MessageBox.h: הגדירו מחלקה בשםMessageBoxשמנהלת מערך הודעות באופן דינמי. המחלקה צריכה לכלול:- מצביע פרטי למערך מחרוזות שהוקצה באופן דינמי
- מספר שלם פרטי שעוקב אחר מספר ההודעות הנוכחי
- מספר שלם פרטי ששומר את הקיבולת המרבית
- בנאי שמקבל קיבולת ומקצה את המערך באמצעות
new[] - הורס שמשחרר כראוי את הזיכרון באמצעות
delete[]ומדפיס"MessageBox destroyed" - מתודה בשם
addMessage(string msg)שמוסיפה הודעה אם יש מקום, ומחזירהtrueבמקרה של הצלחה אוfalseאם המערך מלא - מתודה בשם
printAll()שמדפיסה כל הודעה שמורה בשורה נפרדת
main.cpp: קראו מהקלט ערך של קיבולת ומספר הודעות. לאחר מכן קראו את מספר מחרוזות ההודעה הזה. צרו אובייקטMessageBoxבערימה באמצעותnew, הוסיפו אליו את כל ההודעות, קראו למתודהprintAll(), ואז מחקו כראוי את האובייקט MessageBox כדי לשחרר את הזיכרון.
פורמט הקלט יהיה:
- שורה ראשונה: הקיבולת (מספר שלם)
- שורה שנייה: מספר ההודעות להוספה (מספר שלם)
- השורות הבאות: הודעה אחת בכל שורה
זכרו: לכל new נדרש delete תואם, ולכל new[] נדרש delete[] תואם. לאחר מחיקה, מומלץ להציב nullptr במצביעים.
כללו את קובץ הכותרת שלכם ב־main.cpp באמצעות #include "MessageBox.h".
נסו בעצמכם
#include <iostream>
#include <string>
#include "MessageBox.h"
using namespace std;
int main() {
int capacity;
int numMessages;
// קרא את הקיבולת ואת מספר ההודעות
cin >> capacity;
cin >> numMessages;
cin.ignore(); // נקה את תו השורה החדשה שאחרי המספר
// TODO: צור MessageBox בערימה באמצעות new
// TODO: קרא והוסף את כל ההודעות ל-MessageBox
for (int i = 0; i < numMessages; i++) {
string message;
getline(cin, message);
// הוסף הודעה ל-MessageBox
}
// TODO: קרא ל-printAll() כדי להציג את כל ההודעות
// TODO: מחק את ה-MessageBox כדי לפנות זיכרון
// זכור להגדיר את המצביע ל-nullptr לאחר המחיקה
return 0;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין