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

RAII

مبدأ حجز الموارد كتهيئة RAII

RAII (Resource Acquisition Is Initialization) مبدأ تصميم أساسي بـ C++: اربط عمر أي مورد (ذاكرة، ملف، قفل) بعمر كائن، فيتحرر تلقائيًا وقت خروج النطاق حتى لو حدث استثناء.

بدل ما تفتح ملفًا أو تحجز ذاكرة يدويًا وتتذكر تحريرها بكل مسار ممكن بالكود (بما فيه مسارات الاستثناءات)، RAII يجعل الحجز يحدث بباني الكائن (constructor) والتحرير بهادمه (destructor). لما يخرج الكائن من نطاقه — طبيعيًا أو بسبب استثناء — يُستدعى الهادم تلقائيًا ويحرّر المورد، فما في طريقة لنسيان التحرير.

هذا هو السبب الحقيقي وراء نجاح std::unique_ptr وstd::lock_guard وstd::ifstream: كلها كائنات RAII تُدير موردًا (ذاكرة، قفل، ملف) بشكل تلقائي وآمن.

الصياغة

class Resource {
    Resource() { /* حجز المورد */ }
    ~Resource() { /* تحرير المورد */ }
};

📄 مثال

class FileHandle {
    FILE* f;
public:
    FileHandle(const char* path) { f = fopen(path, "r"); } // حجز بالباني
    ~FileHandle() { if (f) fclose(f); }                     // تحرير بالهادم
};

void readData() {
    FileHandle file("data.txt");
    // حتى لو رُمي استثناء هنا، الهادم يُستدعى تلقائيًا ويُغلق الملف
} // إغلاق تلقائي هنا مهما حدث

أهم النقاط

العنصرالوظيفة
الباني (Constructor)يحجز المورد لحظة إنشاء الكائن
الهادم (Destructor)يحرّر المورد تلقائيًا عند خروج الكائن من نطاقه
أمثلة قياسية على RAIIstd::unique_ptr، std::vector، std::lock_guard، std::ifstream

💡 نصائح عملية

  • اعتبر أي مورد يحتاج تحريرًا (ذاكرة، قفل، اتصال شبكة، ملف) مرشّحًا لتغليفه بكائن RAII
  • std::lock_guard مثال ممتاز: يقفل mutex بالباني ويحرره بالهادم، فيستحيل نسيان فك القفل

⚠️ أخطاء شائعة

  • إدارة موارد يدويًا بـ new/delete أو fopen/fclose مباشرة بدل تغليفها بكائن RAII — عرضة للنسيان خصوصًا مع الاستثناءات
  • الظن أن RAII خاص فقط بالذاكرة — هو مبدأ عام لأي مورد محدود (أقفال، اتصالات، مقابض ملفات)

خصائص ذات صلة

🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار CPP الكامل بالعربي.