זיכרון Stack לעומת Heap
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 12 מתוך 104.
תוכניות C++ משתמשות בשני אזורי זיכרון עיקריים: מחסנית וערימה. הבנת המקום שבו האובייקטים שלך נמצאים חיונית לכתיבת קוד יעיל ונטול באגים.
המחסנית היא זיכרון מהיר ואוטומטי. משתנים שמוכרזים בתוך פונקציות נמצאים בה, ומושמדים אוטומטית כשהם יוצאים מתחום ההכרה שלהם.
void example() {
int x = 10; // הקצאה במחסנית
Player player; // הקצאה במחסנית - מושמד אוטומטית
} // x ו-player מושמדים כאןהערימה היא זיכרון גדול יותר אך איטי יותר, שאותו מנהלים ידנית. אובייקטים בערימה נשארים קיימים עד שמוחקים אותם במפורש.
void example() {
Player* player = new Player(); // הקצאה בערימה
// player קיים עד למחיקתו
delete player; // נדרש שחרור ידני של הזיכרון
}הבדלים עיקריים:
| מחסנית | ערימה |
|---|---|
| הקצאה מהירה | הקצאה איטית יותר |
| גודל מוגבל | קיבולת גדולה |
| ניקוי אוטומטי | נדרש ניקוי ידני |
| אובייקטים בגודל קבוע | אובייקטים בגודל דינמי |
השתמשו בהקצאה במחסנית עבור אובייקטים קטנים וקצרי־חיים. השתמשו בהקצאה בערימה כאשר אובייקטים צריכים להתקיים מעבר לתחום שלהם או כאשר הגודל שלהם נקבע בזמן ריצה.
שכחה של שחרור זיכרון בערימה גורמת לדליפות זיכרון, מקור נפוץ לבאגים בתוכניות C++.
אתגר
קלנחקור את ההבדל בין זיכרון המחסנית לזיכרון הערימה באמצעות בניית מחלקת Counter פשוטה, שעוקבת אחר יצירת אובייקטים והשמדתם.
תיצור שני קבצים כדי לארגן את הקוד שלך:
Counter.h: הגדר מחלקתCounterעם מאפיין פרטי בשםname(מחרוזת). כלול בנאי שמקבל שם ומדפיס"Creating: <name>", וכן מפרק שמדפיס"Destroying: <name>". הוסף מתודה בשםgetName()שמחזירה את שם המונה.main.cpp: הדגם הקצאה הן במחסנית והן בערימה. קרא שם מהקלט, ואז:- צור
Counterשיוקצה במחסנית, באמצעות השם הזה - צור
Counterשיוקצה בערימה, עם השם"HeapCounter" - הדפס את שמות שני המונים בפורמט
"Stack: <name>"ו-"Heap: <name>" - מחק את המונה שהוקצה בערימה כדי למנוע דליפת זיכרון
- צור
שים לב כיצד הודעות הבנאי והמפרק מופיעות בסדרים שונים, בהתאם למועד שבו יוצרים ומוחקים כל אובייקט. אובייקט המחסנית יושמד אוטומטית כאשר main() מסתיימת, ואילו את אובייקט הערימה צריך למחוק במפורש.
כלול את קובץ הכותרת שלך ב-main.cpp באמצעות #include "Counter.h".
נסו בעצמכם
#include <iostream>
#include <string>
#include "Counter.h"
using namespace std;
int main() {
// קרא את השם מהקלט
string inputName;
cin >> inputName;
// TODO: צור Counter שמוקצה במחסנית באמצעות inputName
// TODO: צור Counter שמוקצה בערימה בשם "HeapCounter"
// TODO: הדפס את שם המונה שבמחסנית בפורמט "Stack: <name>"
// TODO: הדפס את שם המונה שבערימה בפורמט "Heap: <name>"
// TODO: מחק את המונה שמוקצה בערימה כדי למנוע דליפת זיכרון
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++ אונליין