Menu
Coddy logo textTech

RAII ב-C++

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

RAII (רכישת משאבים היא אתחול) הוא דפוס יסודי ב־C++ שבו ניהול המשאבים קשור למשך החיים של האובייקט. הרעיון פשוט: רוכשים משאבים בבנאי ומשחררים אותם במפרק.

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

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // רכישת משאב
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // שחרור משאב
    }
};

עם RAII, לעולם לא שוכחים לנקות:

void processFile() {
    FileHandler handler("data.txt");  // המשאב הוקצה
    // עבודה עם הקובץ...
    // אם נזרקת כאן חריגה, ה-destructor עדיין מופעל!
}   // המשאב משוחרר אוטומטית

מצביעים חכמים הם דוגמה מושלמת ל־RAII בפעולה. unique_ptr מקבל בעלות על זיכרון בערימה בבנאי שלו ומשחרר אותו במפרק שלו. כבר השתמשת ב־RAII בלי לשים לב!

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

challenge icon

אתגר

קל

בואו נבנה מנהל חיבורים שמדגים RAII באמצעות טיפול אוטומטי במחזור החיים של חיבורים דמויי רשת. כאשר נוצר חיבור, עליו "open", וכשהוא יוצא מתחום הנראות, עליו "close" באופן אוטומטי: אין צורך בניקוי ידני!

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

  • Connection.h: הגדירו מחלקה Connection שמנהלת משאב חיבור באמצעות עקרונות RAII. למחלקה צריכים להיות:
    • מאפיין פרטי connectionId (מחרוזת) לזיהוי החיבור
    • מאפיין פרטי isOpen (bool) למעקב אחר מצב החיבור
    • בנאי שמקבל מזהה חיבור, מגדיר את isOpen לערך true ומדפיס "Opening connection: <id>"
    • הורס שבודק אם החיבור פתוח, סוגר אותו באמצעות הגדרת isOpen לערך false, ומדפיס "Closing connection: <id>"
    • מתודה send(string message) שמדפיסה "[<id>] Sending: <message>" אם החיבור פתוח
    • מתודה getId() שמחזירה את מזהה החיבור
  • main.cpp: הדגימו כיצד RAII מבטיח ניקוי אוטומטי באמצעות קריאת מזהה חיבור והודעה מהקלט. לאחר מכן:
    • צרו תחום נראות באמצעות סוגריים מסולסלים { }
    • בתוך התחום הזה, צרו אובייקט Connection במחסנית עם מזהה הקלט
    • השתמשו בחיבור כדי לשלוח את הודעת הקלט
    • תנו לתחום הנראות להסתיים (החיבור אמור להיסגר אוטומטית)
    • אחרי תחום הנראות, הדפיסו "Connection out of scope"

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

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

נסו בעצמכם

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

using namespace std;

int main() {
    string connectionId;
    string message;
    
    // קראו קלט
    cin >> connectionId;
    cin.ignore();
    getline(cin, message);

    // TODO: צרו תחום בעזרת סוגריים מסולסלים { }
    // בתוך התחום:
    //   - צרו אובייקט Connection על המחסנית עם connectionId
    //   - השתמשו בחיבור כדי לשלוח את ההודעה
    // אפשרו לתחום להסתיים (ה-destructor ייקרא אוטומטית)

    // TODO: לאחר שהתחום מסתיים, הדפיסו "Connection out of scope"

    return 0;
}
quiz iconבחנו את עצמכם

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

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

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