RAII اختصار لـ Resource Acquisition Is Initialization — أهم مبدأ تصميم
في C++ للتعامل الآمن مع أي مورد محدود، ومصدر الأمان وراء أدوات مثل
unique_ptr وlock_guard.
المشكلة التي يحلّها RAII
بدون RAII، إدارة مورد مثل الذاكرة أو الملف تعتمد على تذكّرك اليدوي للتحرير في كل مسار ممكن بالكود:
void riskyFunction() {
FILE* f = fopen("data.txt", "r");
if (someErrorCondition()) {
return; // ❌ تسريب! نسينا fclose هنا
}
processFile(f); // لو رمت هذه استثناءً، fclose التالي لن يُنفَّذ أبدًا
fclose(f);
}
كل نقطة خروج محتملة (return مبكّر، استثناء) تحتاج تذكّرًا يدويًا للتحرير — وهذا عرضة للنسيان بمشاريع كبيرة.
فكرة RAII
اربط عمر المورد بعمر كائن: احجزه بالباني (constructor)، وحرّره بالهادم (destructor). لما يخرج الكائن من نطاقه — طبيعيًا أو بسبب استثناء — يُستدعى الهادم تلقائيًا:
class FileHandle {
FILE* f;
public:
FileHandle(const char* path) {
f = fopen(path, "r"); // حجز المورد بالباني
}
~FileHandle() {
if (f) fclose(f); // تحرير المورد بالهادم — دائمًا يُنفَّذ
}
};
void safeFunction() {
FileHandle file("data.txt");
if (someErrorCondition()) {
return; // ✅ الهادم يُستدعى تلقائيًا هنا، الملف يُغلق دائمًا
}
processFile(file);
} // ✅ إغلاق تلقائي هنا أيضًا مهما حدث
لا حاجة لتذكّر أي شيء — الهادم يعمل دائمًا، بضمان اللغة نفسها.
أمثلة RAII بالمكتبة القياسية
معظم أدوات C++ الحديثة الآمنة هي فعليًا كائنات RAII:
| الكائن | المورد المُدار |
|---|---|
std::unique_ptr / std::shared_ptr | ذاكرة على الكومة |
std::vector / std::string | ذاكرة داخلية ديناميكية |
std::lock_guard | قفل mutex |
std::ifstream / std::ofstream | مقبض ملف |
مثال lock_guard — أهم استخدام في البرمجة المتزامنة:
#include <mutex>
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx); // يقفل هنا
counter++;
} // يفكّ القفل تلقائيًا هنا — يستحيل نسيان فكّه حتى مع استثناء
RAII مقابل جامع القمامة
لغات مثل Java وPython تحل مشكلة الذاكرة بجامع قمامة (Garbage Collector) يعمل بالخلفية. C++ لا تملك جامع قمامة بشكل افتراضي، فـ RAII هو الحل المكافئ — وميزته أنه يعمم الفكرة لأي مورد، لا الذاكرة فقط: أقفال، اتصالات، مقابض ملفات، كلها تستفيد من نفس المبدأ بلا انتظار دورة تنظيف لاحقة.
الخلاصة
RAII ليس ميزة لغوية منفصلة بل نمط استخدام لباني وهادم الصنف. أي مرة تدير موردًا يدويًا بكودك، اسأل نفسك: هل يمكن تغليفه بكائن يحرّره تلقائيًا؟ الجواب غالبًا نعم — وهذا بالضبط سرّ أمان C++ الحديثة رغم غياب جامع القمامة.
اقرأ أكثر عن المؤشّرات الذكية والذاكرة الديناميكية في مسار C++ الكامل.