ספריית בעלות - פרויקט
פרויקט - בעלים אחד לכל משאב¶
בפרויקט נבנה ספרייה קטנה שמנהלת שלושה סוגי משאבים: event של Windows, socket של Winsock ומערך bytes. המטרה היא שהמשתמש בספרייה יוכל להעביר בעלות ולהשאיל גישה בלי לזכור בכל מקום את פרטי הניקוי.
הפרויקט מחבר את חיי האובייקטים, move, תצוגות ובדיקות כשל שלמדנו. הוא אינו דורש לכתוב שרת רשת או לתזמן threadים; ה־socket וה־event משמשים כרגע לבדיקת חוזי משאבים אמיתיים.
החוזים שמקבלים מראש¶
הפונקציה CreateEventW יוצרת event ומחזירה HANDLE. כישלון מיוצג ב־null, ומשאב שהתקבל בהצלחה נסגר באמצעות CloseHandle. אין לסגור ערך כשל ואין להעתיק את המספר של הhandle לשני בעלים.
הפונקציה socket פועלת אחרי WSAStartup ומחזירה SOCKET. כישלון מיוצג ב־INVALID_SOCKET, והניקוי מתבצע באמצעות closesocket, לא CloseHandle. כל ה־socketים בפרויקט צריכים להיסגר לפני WSACleanup.
מערך bytes שמוקצה באמצעות make_unique משתמש בהתמחות המערך של unique_ptr. התצוגה אליו היא span שמכיל גודל, אך אינה שומרת את הבעלים בחיים.
ממשק נדרש¶
הגדירו בעלים של event ובעלים של socket, עם בנייה ריקה, אימוץ משאב תקף, destructor, move constructor ו־move assignment. אפשר להשתמש בשתי מחלקות מפורשות, או בתבנית בעלים קטנה שמקבלת policy של ניקוי. אין דרישה להמציא framework כללי.
הפעולה get מחזירה גישה מושאלת. הפעולה release מעבירה אחריות לקורא ומשאירה את הבעלים ריק. הפעולה reset מנקה את המשאב הישן ומתקינה משאב אחר לפי חוזה מפורש. יש לדחות copy בזמן קומפילציה.
הגדירו גם Buffer עם גודל ותצוגה לקריאה או לכתיבה. אחרי move המקור צריך להיות ריק גם מבחינת pointer וגם מבחינת גודל, כדי שלא יחזיר span לא תקף.
תרחישים שחייבים לעבור¶
בדקו scope רגיל, return מוקדם, move אל יעד ריק ו־move אל יעד שכבר מחזיק משאב. בדקו self-move לפי החוזה שבחרתם, וכן release שאחריו בעלים חדש מקבל אחריות.
הוסיפו כשל יזום אחרי יצירת event ולפני סוף יצירת אובייקט שמכיל כמה משאבים. ודאו שהמשאב הראשון נסגר גם כשהבנייה הכוללת נכשלת. אפשר להשתמש בחריגה מכוונת בתוכנית המעבדה כדי להפעיל את המסלול בלי להסתמך על מחסור אקראי במשאבי מערכת.
כתבו שתי בדיקות קומפילציה שליליות שמנסות להעתיק בעלים. שמרו אותן בקבצים נפרדים מהתוכנית התקינה, והסבירו מה בדיוק אמור להידחות.
הוכחת בעלות¶
צרפו תרשים קצר של כל תרחיש: מי מחזיק את המשאב לפני הפעולה, מי מחזיק אותו אחריה ומתי הניקוי קורה. ציינו לכל פעולה אם היא יכולה להיכשל ומה מצב האובייקט לאחר הכשל.
אין צורך להוכיח באמצעות שימוש בhandle שכבר נסגר שהוא אכן נסגר. אפשר לבדוק מוני פתיחה וסגירה בשכבת policy בדוקה, ולהשוות תצפית בכלי מערכת. שימוש במשאב לא תקף אינו בדיקת קבלה טובה.
מסירה¶
מגישים headers, תוכנית בדיקה, הוראות בנייה ב־MSVC x64 ודוח שמפריד בדיקות שבוצעו מניתוח שלא הורץ. ציינו במפורש שה־destructorים מספקים ניקוי ואינם ממשק לדיווח על כשל סגירה; אם הוספתם close מפורש, תעדו את מדיניות השגיאה שלו.
תנאי המעבר הוא בעלות יחידה שמוכחת בכל מסלול, בלי copy מקרי, double close או span חיובי עם pointer ריק. הקוד צריך להיות קטן מספיק כדי להסביר כל פעולה בו.