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

noexcept

ضمان عدم رمي الاستثناءات noexcept

noexcept تصريح يؤكد أن دالة معيّنة لن ترمي أي استثناء إطلاقًا — إن خالفت الوعد، يستدعي البرنامج std::terminate فورًا بدل معالجة الاستثناء عاديًا.

تعليم دالة بـ noexcept يمنح المترجم فرصة تحسينات أداء (خصوصًا مع move constructors التي تحتاج ضمان noexcept لتُستخدم فعليًا بدل النسخ الاحتياطي بحاويات STL أثناء إعادة التحجيم)، ويوثّق نية واضحة للمبرمجين الآخرين. لكنه وعد صارم: لو رمت الدالة استثناءً فعليًا رغم noexcept، البرنامج يتوقف فورًا عبر std::terminate بدل أي معالجة اعتيادية — لا rollback ولا catch يعمل.

الصياغة

ReturnType funcName(params) noexcept;

📄 مثال

class Buffer {
    int* data;
public:
    // move constructor بـ noexcept — يسمح لـ std::vector باستخدامه بأمان أثناء إعادة التحجيم
    Buffer(Buffer&& other) noexcept : data(other.data) {
        other.data = nullptr;
    }
};

void safeDivide(int a, int b) noexcept {
    if (b == 0) std::terminate(); // بدل رمي استثناء ممنوع هنا
}

أهم النقاط

العنصرالوظيفة
noexceptيعد صراحة بعدم رمي أي استثناء — مخالفته تستدعي std::terminate فورًا
noexcept(expr)شرطي — الدالة noexcept فقط إذا تحقق التعبير وقت الترجمة
move constructor + noexceptأهم استخدام عملي — يتيح لحاويات STL استخدام move بدل copy عند إعادة التحجيم

💡 نصائح عملية

  • علّم move constructor وmove assignment بـ noexcept دائمًا متى أمكن — فرق أداء حقيقي وملموس مع std::vector
  • لا تضع noexcept على دالة قد ترمي استثناءً فعليًا (مثل دوال تتعامل مع ملفات أو شبكة) إلا إذا تعالج كل الأخطاء داخليًا

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

  • وضع noexcept على دالة ترمي استثناءً أحيانًا (مثل دالة تخصّص ذاكرة قد تفشل) — يحوّل استثناءً طبيعيًا لانهيار فوري للبرنامج
  • نسيان noexcept على move constructor فتقرر حاويات STL استخدام النسخ الأبطأ بدل النقل كإجراء أمان احترازي

خصائص ذات صلة

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