דילוג לתוכן המרכזי
מודול 7 · שיעור 2 מתוך 216/18 בקורס~12 min
שיעורי מודול (2/2)

std::weak_ptr

למרות ש-std::shared_ptr שימושי ביותר, הסתמכות על בעלות משותפת בלבד יכולה להוביל לבעיה המכונה הפניה מעגלית (או תלות מחזורית).

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

מה זה std::weak_ptr

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

היא אינה הבעלים של המשאב ישירות, ולכן היא אינה מונעת את השמדתו.

C++
#include <memory>

std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared; // Does not increment reference count!

אימות וגישה למשאב

מכיוון ש-weak_ptr אינו הבעלים של המשאב, ניתן לבטל את הקצאת המשאב בכל עת (כאשר כל המופעים המשויכים shared_ptr יוצאים מהתחום).

כדי להשתמש במשאב הנצפה, עלינו:

  1. בדוק אם הוא עדיין בתוקף באמצעות expired().
  2. המר באופן זמני את weak_ptr ל-shared_ptr באמצעות שיטת lock(). אם המשאב עדיין פעיל, lock() מחזיר shared_ptr חוקי, אחרת הוא מחזיר מצביע null (nullptr).
C++
if (!weak.expired()) {
    // lock() creates a temporary shared_ptr to ensure safe access
    if (std::shared_ptr<int> sharedAccess = weak.lock()) {
        std::cout << *sharedAccess << std::endl;
    }
} else {
    std::cout << "Resource deallocated!" << std::endl;
}

נסה זאת בעצמך

פעילות גופנית#cpp.m7.l2.e1
ניסיונות: 0טוען...

הכריז על std::weak_ptr<int> בשם wPtr אותחל מ-sPtr. לאחר מכן הדפס את התוצאה הבוליאנית שהוחזרה על ידי wPtr.expired() באמצעות std::cout.

טוען עורך...
הצג רמז

הכריז על ה-'weak_ptr' המציין את אותו סוג גנרי '<int>' והקצה לו 'sPtr' ישירות.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#cpp.m7.l2.e2
ניסיונות: 0טוען...

השתמש בשיטת lock() ב-wPtr כדי להשיג shared_ptr זמני. אם הפעולה מצליחה (המצביע אינו ריק), הדפס את הערך שחסר.

טוען עורך...
הצג רמז

אתחול משתנה בתוך בלוק `if` על ידי קריאה `wPtr.lock()`, ולאחר מכן הדפס את המשאב המפנה אותו עם הכוכבית `*`.

הפתרון זמין לאחר 3 ניסיונות