الانتقال إلى المحتوى الرئيسي
الوحدة 7 · الدرس 2 من 216/18 في الدورة~12 min
دروس الوحدة (2/2)

الأمراض المنقولة جنسيا::weak_ptr

على الرغم من أن std::shared_ptr مفيد للغاية، إلا أن الاعتماد فقط على الملكية المشتركة يمكن أن يؤدي إلى مشكلة تُعرف باسم المرجع الدائري (أو التبعية الدورية).

إذا كان كل كائنين أو أكثر يحتوي كل منهما على shared_ptr يشير إلى الآخر، فسيتم إنشاء حلقة مغلقة. في هذه الحالة، لن يصل العدد المرجعي لأي من الكائنين إلى الصفر، مما يمنع إلغاء التخصيص ويتسبب في حدوث تسرب للذاكرة.

ما هو محمي_INLINE_2

لكسر دورات الملكية، توفر المكتبة القياسية 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 صالحًا، وإلا فإنه يُرجع مؤشرًا فارغًا (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 من المحاولات