تخطَّ إلى المحتوى

١٦ يوليو ٢٠٢٦

المؤشّرات الذكية في C++ بالعربي (Smart Pointers)

شارك المقال:

قبل C++11، كل ذاكرة تُحجز بـ new يجب تحريرها يدويًا بـ delete — ونسيان ذلك أشهر مصدر أخطاء اللغة تاريخيًا. المؤشّرات الذكية حلّت هذه المشكلة جذريًا.

المشكلة الأصلية

void riskyFunction() {
    int* data = new int[1000];

    if (someCondition()) {
        return; // ❌ تسريب ذاكرة! نسينا delete[] هنا
    }

    delete[] data;
}

كل نقطة خروج ممكنة من الدالة (return مبكّر، استثناء) تحتاج تذكّر delete — عرضة للنسيان بمشاريع كبيرة، ومصدر تسريبات الذاكرة الشهيرة بـ C++.

unique_ptr — الملكية الحصرية

المؤشّر الذكي الافتراضي والأكثر استخدامًا. كائن واحد فقط يملك المورد، ويُحرَّر تلقائيًا عند خروجه من نطاقه:

#include <memory>

void safeFunction() {
    std::unique_ptr<int[]> data = std::make_unique<int[]>(1000);

    if (someCondition()) {
        return; // ✅ يتحرّر تلقائيًا هنا، بلا delete يدوي
    }
} // ✅ يتحرّر هنا أيضًا مهما حدث

لا يمكن نسخ unique_ptr — الملكية حصرية دائمًا:

std::unique_ptr<int> a = std::make_unique<int>(5);
// std::unique_ptr<int> b = a; // ❌ خطأ ترجمة متعمَّد

std::unique_ptr<int> b = std::move(a); // ✅ نقل الملكية مسموح
// a أصبح nullptr الآن

shared_ptr — الملكية المشتركة

لما يحتاج أكثر من جزء بالبرنامج امتلاك نفس الكائن معًا، عبر عدّاد مراجع داخلي يحرّر الذاكرة عند وصوله للصفر:

std::shared_ptr<int> a = std::make_shared<int>(42);
std::cout << a.use_count(); // 1

{
    std::shared_ptr<int> b = a; // نسخ مسموح، العدّاد = 2
} // b يخرج من النطاق، العدّاد يعود = 1

weak_ptr — كسر دورات المراجع

مشكلة shared_ptr: لو كائنان يشير كل منهما للآخر، عدّاد المراجع لن يصل للصفر أبدًا — تسريب صامت. weak_ptr يراقب الكائن دون زيادة العدّاد:

struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev; // weak يكسر الدورة
};

جدول المقارنة السريع

النوعالملكيةالتكلفةيُستخدم متى
unique_ptrحصريةشبه معدومةافتراضيًا دائمًا
shared_ptrمشتركةعدّاد مراجعملكية مشتركة فعلية
weak_ptrمراقبة فقطشبه معدومةكسر دورات المراجع
مؤشّر خام (new/delete)يدوية بالكاملنادرًا، بكود حديث

القاعدة العملية

ابدأ دائمًا بـ unique_ptr. انتقل لـ shared_ptr فقط لو اكتشفت فعليًا أن أكثر من جزء بالكود يحتاج امتلاك نفس الكائن بنفس الوقت. تجنّب new/delete المباشرة تمامًا في كود C++ حديث إلا لحالات نادرة جدًا.

تعمّق أكثر بدرس المؤشّرات الذكية الكامل أو اقرأ عن مبدأ RAII الذي يقوم عليه كل هذا.

📚 مصادر رسمية للتعمّق: مرجع C++ الرسمي

الأسئلة الشائعة

لماذا لا نستخدم new وdelete مباشرة دائمًا؟

لأن نسيان delete يسبب تسريب ذاكرة، واستخدام مؤشّر بعد تحريره يسبب انهيار البرنامج. المؤشّرات الذكية تحرّر الذاكرة تلقائيًا فتزيل هذين الخطرين بالكامل.

متى أستخدم shared_ptr بدل unique_ptr؟

فقط عندما تحتاج فعليًا أكثر من مالك حقيقي لنفس الكائن بنفس الوقت. إن كان مالك واحد يكفي، unique_ptr أخف أداءً وأوضح نية.

هل المؤشّرات الذكية تبطئ البرنامج؟

unique_ptr بلا أي تكلفة أداء إضافية تقريبًا مقارنة بمؤشّر خام. shared_ptr له تكلفة بسيطة بسبب عدّاد المراجع، لكنها غالبًا لا تُذكر مقارنة بأمان الذاكرة الذي توفّره.

اقرأ أيضًا

تصفّح كل المقالات في المدوّنة، أو ابدأ التعلّم من المسارات و خرائط الطريق.