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++ מבטיחה ניקוי דטרמיניסטי ומבטלת קטגוריות שלמות של באגים, כמו דליפות ומזהים תלויים.
אתגר
קלבואו נבנה מנהל חיבורים שמדגים 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;
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
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++ אונליין