مشكلة new/delete اليدوية
تعلّمت سابقًا new وdelete لإدارة الذاكرة الديناميكية — لكنها تحمّلك
مسؤولية كاملة: نسيان delete يسبب تسريب ذاكرة، واستخدام مؤشّر بعد حذفه يسبب
انهيارًا:
void risky() {
int* p = new int(42);
if (someCondition()) return; // ❌ تسريب! نسينا delete هنا
delete p;
}
المؤشّرات الذكية تحل هذا بتطبيق مبدأ RAII: الذاكرة تتحرر تلقائيًا عند خروج
الكائن من نطاقه، حتى لو حدث استثناء أو return مبكّر.
std::unique_ptr — الملكية الحصرية
الخيار الافتراضي لإدارة أي ذاكرة ديناميكية. كائن واحد فقط يملك المورد:
#include <memory>
std::unique_ptr<int> p = std::make_unique<int>(42);
cout << *p; // 42
// std::unique_ptr<int> p2 = p; // ❌ خطأ ترجمة — النسخ ممنوع
std::unique_ptr<int> p2 = std::move(p); // ✅ نقل الملكية
// p الآن nullptr، p2 يملك القيمة
} // p2 يتحرّر تلقائيًا هنا — بلا delete يدوي
مع أصنافك الخاصة:
class Report {
string title;
public:
Report(string t) : title(t) { cout << "أُنشئ: " << title << "\n"; }
~Report() { cout << "تحرّر: " << title << "\n"; }
};
void generate() {
auto r = std::make_unique<Report>("تقرير 2026");
} // "تحرّر: تقرير 2026" يُطبع تلقائيًا هنا
std::shared_ptr — الملكية المشتركة
لما يحتاج أكثر من جزء بالبرنامج امتلاك نفس الكائن معًا. يستخدم عدّاد مراجع داخليًا:
std::shared_ptr<int> a = std::make_shared<int>(42);
cout << a.use_count(); // 1
{
std::shared_ptr<int> b = a; // نسخ مسموح — العدّاد يصبح 2
cout << a.use_count(); // 2
} // b يخرج من النطاق، العدّاد يعود لـ 1
cout << a.use_count(); // 1
// الذاكرة تتحرّر تلقائيًا لما يصل العدّاد للصفر
std::weak_ptr — كسر دورة المراجع
لو كائنان يشير كل منهما للآخر بـ shared_ptr، عدّاد المراجع لن يصل للصفر
أبدًا (تسريب صامت). weak_ptr يراقب الكائن دون زيادة العدّاد:
struct Node {
shared_ptr<Node> next;
weak_ptr<Node> prev; // weak لكسر الدورة
};
auto a = make_shared<Node>();
auto b = make_shared<Node>();
a->next = b;
b->prev = a; // لا يزيد عدّاد a
if (auto p = b->prev.lock()) { // lock() يُرجع shared_ptr مؤقّت
cout << "الأب ما زال موجودًا";
}
جدول المقارنة
| النوع | الملكية | يُستخدم متى |
|---|---|---|
unique_ptr | حصرية (مالك واحد) | الخيار الافتراضي دائمًا |
shared_ptr | مشتركة (عدّاد مراجع) | عدة أجزاء تملك نفس الكائن فعليًا |
weak_ptr | مراقبة بلا ملكية | كسر دورات المراجع |
أخطاء شائعة
- استخدام
shared_ptrبكل مكان افتراضيًا بدلunique_ptr— تكلفة أداء غير ضرورية. - إنشاء
shared_ptrمن نفس المؤشّر الخام مرتين بشكل منفصل — يسبب حذفًا مزدوجًا. - استخدام
get()لحذف المؤشّر يدويًا — يتعارض مع التحرير التلقائي ويسبب انهيارًا.
🎯 التالي: تعبيرات لامدا — دوال مجهولة الاسم تكتبها inline مباشرة.