Menu
Coddy logo textTech

מעמיקים בנושא הורסים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 24 מתוך 104.

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

למחסל יש שם זהה לשם המחלקה, עם סימן טילדה ~ לפניו. הוא לא מקבל פרמטרים ואין לו טיפוס החזרה:

class FileHandler {
    std::string filename;
    int* buffer;
public:
    FileHandler(std::string name, size_t size) 
        : filename(name), buffer(new int[size]) {
        std::cout << "Opening " << filename << "\n";
    }
    ~FileHandler() {
        delete[] buffer;
        std::cout << "Closing " << filename << "\n";
    }
};

הורסים נקראים באופן אוטומטי במצבים הבאים:

  • אובייקטים במחסנית יוצאים מתחום החיים שלהם
  • מפעילים את delete על אובייקט שהוקצה בערימה
  • משך החיים של אובייקט זמני מסתיים
void example() {
    FileHandler f1("data.txt", 100);    // הבנאי נקרא
    FileHandler* f2 = new FileHandler("log.txt", 50);
    delete f2;                           // המפרק נקרא עבור f2
}   // המפרק נקרא עבור f1 (יוצא מטווח ההכרה)

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

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

challenge icon

אתגר

קל

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

תיצרו שני קבצים כדי לארגן את הקוד:

  • Session.h: הגדירו מחלקה בשם Session שמייצגת הפעלת משתמש פעילה עם נתונים שהוקצו באופן דינמי. למחלקה צריכים להיות:
    • שדות פרטיים: username (מחרוזת), sessionId (מספר שלם), ומצביע למערך של מספרים שלמים בשם activityLog שעוקב אחר פעולות המשתמש, וכן logSize עבור גודל המערך
    • בנאי שמקבל שם משתמש, מזהה הפעלה וגודל יומן. עליו להקצות את מערך יומן הפעילות בערימה, לאתחל את כל האיברים ל-0 ולהדפיס "Session <sessionId> started for <username>"
    • הורס שמשחרר את הזיכרון שהוקצה ומדפיס "Session <sessionId> ended for <username>"
    • מתודה logActivity(int activityCode) ששומרת את קוד הפעילות במקום הפנוי הבא (עקבו אחר המיקום הנוכחי באופן פנימי); אם היומן כבר מלא, הקריאה מתעלמת, כך שהמספר לעולם לא יעלה על גודל היומן
    • מתודה getActivityCount() שמחזירה כמה פעילויות נרשמו
    • מתודה getUsername() שמחזירה את שם המשתמש
  • main.cpp: הדגימו את התנהגות ההורס בתרחישים שונים. קראו מהקלט שם משתמש וגודל יומן (כל אחד בשורה נפרדת), ואז:
    • צרו בלוק תחום באמצעות סוגריים מסולסלים { }, ובתוכו צרו אובייקט Session שהוקצה במחסנית, עם שם המשתמש מהקלט, מזהה הפעלה 101 וגודל היומן מהקלט. רשמו שתי פעילויות עם הקודים 1 ו-2, ואז הדפיסו "Stack session activities: <count>". כשהבלוק מסתיים, ההורס אמור לפעול באופן אוטומטי.
    • אחרי הבלוק, הדפיסו "Stack session destroyed"
    • צרו אובייקט Session שהוקצה בערימה באמצעות new, עם שם המשתמש "Guest", מזהה הפעלה 202 וגודל יומן 3. רשמו פעילות אחת עם הקוד 5, הדפיסו "Heap session activities: <count>", ואז בצעו לו delete במפורש.
    • אחרי המחיקה, הדפיסו "Heap session destroyed"

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

כללו את קובץ הכותרת ב-main.cpp באמצעות #include "Session.h".

נסו בעצמכם

#include <iostream>
#include <string>
#include "Session.h"

using namespace std;

int main() {
    // קראו את הקלט
    string username;
    int logSize;
    getline(cin, username);
    cin >> logSize;
    
    // TODO: צרו בלוק תחום עם סוגריים מסולסלים { }
    // בתוך הבלוק:
    //   - צרו Session המוקצה במחסנית עם שם המשתמש מהקלט, מזהה ההפעלה 101 וגודל היומן מהקלט
    //   - רשמו ביומן שתי פעילויות עם הקודים 1 ו-2
    //   - הדפיסו "Stack session activities: <count>"
    // כשהבלוק מסתיים, ה-destructor פועל אוטומטית
    
    // TODO: אחרי הבלוק, הדפיסו "Stack session destroyed"
    
    // TODO: צרו Session המוקצה בערימה באמצעות new
    //   - שם משתמש: "Guest", מזהה הפעלה: 202, גודל יומן: 3
    //   - רשמו ביומן פעילות אחת עם הקוד 5
    //   - הדפיסו "Heap session activities: <count>"
    //   - מחקו את ההפעלה
    
    // TODO: לאחר המחיקה, הדפס "Heap session destroyed"
    
    return 0;
}
quiz iconבחנו את עצמכם

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

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר C++ אונליין