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 الكامل بالعربي.