معالجة الأخطاء في C++: try/catch والتقنيات المتقدمة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

معالجة الأخطاء المتقدمة في C++: من try/catch إلى الممارسات الصناعية



معالجة الأخطاء هي أحد الركائز الأساسية للبرمجة الصناعية. في C++، لا يتوفر للمطور الآلية الكلاسيكية try/catch فحسب، بل أيضًا ترسانة كاملة من التقنيات المتقدمة: من RAII إلى ضمانات أمان الاستثناءات. في هذه المقالة، سنشرح كيفية كتابة كود C++ موثوق يعالج الأعطال بشكل صحيح، ولا يتسرب منه الموارد، ويظل قابلاً للقراءة.



1. الأساسيات والمزالق القياسية لـ try/catch



الصيغة الأساسية مألوفة للجميع:



#include <iostream>#include <stdexcept>

void dangerousFunction(int value) { if (value < 0) { throw std::invalid_argument("يجب أن تكون القيمة غير سالبة"); } // ... العمل مع value}

int main() { try { dangerousFunction(-5); } catch (const std::invalid_argument& e) { std::cerr << "خطأ: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "خطأ عام: " << e.what() << std::endl; } catch (...) { std::cerr << "تم اكتشاف استثناء غير معروف" << std::endl; } return 0;}


نقاط مهمة:

  • التقط بالمرجع — catch (const std::exception& e) يتجنب تقطيع الكائنات.
  • ترتيب كتل catch مهم: أولاً الاستثناءات الأكثر تحديدًا، ثم العامة.
  • لا تفرط في استخدام catch (...) — فهو يخفي جميع الأخطاء، بما في ذلك الحرجة (مثل std::bad_alloc).
  • لا ترمِ الاستثناءات أبدًا من المدمرات — يؤدي هذا إلى سلوك غير محدد (عادةً إلى إنهاء طارئ).


2. RAII كبديل لـ try/catch لإدارة الموارد



RAII (اكتساب الموارد هو التهيئة) — هو النمط الرئيسي في C++ الذي يجعل الاستثناءات آمنة. الفكرة: يتم الاستحواذ على المورد في المُنشئ وتحريره في المُدمّر. إذا حدث استثناء، يتم استدعاء مدمرات جميع الكائنات المنشأة تلقائيًا (تفكيك المكدس).



#include <fstream>#include <vector>#include <stdexcept>

void processFile(const std::string& filename) { std::ifstream file(filename); // RAII: سيتم فتح الملف في المُنشئ if (!file.is_open()) { throw std::runtime_error("لا يمكن فتح الملف: " + filename); }

std::vector<int> data; int value; while (file >> value) { data.push_back(value); } // مُدمّر file سيغلق الملف تلقائيًا، // حتى في حالة حدوث استثناء (مثل bad_alloc أثناء push_back)}


مزايا RAII على try/catch اليدوي:

  • لا حاجة لكتابة كتل finally — المدمرات تضمن التنظيف.
  • يصبح الكود أكثر خطية وقابلية للقراءة.
  • الاستثناءات لا تؤدي إلى تسرب الذاكرة، واصفات الملفات، إلخ.


3. ضمانات أمان الاستثناءات



في C++، من المعتاد التمييز بين ثلاثة مستويات من الضمانات للدوال:



  • ضمان عدم الرمي — الدالة لا ترمي استثناءات أبدًا. يتم تمييزها بـ noexcept.
  • الضمان القوي — إذا حدث استثناء، تظل حالة البرنامج دون تغيير (عملية ذرية).
  • الضمان الأساسي — عند حدوث استثناء، لا يحدث تسرب للموارد، وتبقى الكائنات في حالة متسقة، لكن قيمتها قد تتغير.


مثال مع الضمان القوي (طريقة copy-and-swap):



#include <algorithm>  // لـ std::swap#include <vector>#include <stdexcept>

class SafeVector { std::vector<int> data_;public: void push_back(int value) { // 1. يتم إنشا

المدونات

توصيات الكتب