مقدمة: لماذا لغة C++ صعبة ولكنها مثيرة للاهتمام
لغة C++ هي واحدة من أقوى لغات البرمجة وأكثرها أداءً. لكن القوة العظيمة تأتي بمسؤولية كبيرة. غالبًا ما يواجه المطورون المبتدئون أخطاءً يمكن أن تؤدي إلى تعطل البرنامج، وتسرب الذاكرة، وسلوك غير محدد. في هذه المقالة، سنقوم بتفصيل أكثر 10 أخطاء شائعة يرتكبها المبتدئون في لغة C++ — من الألف إلى الياء. ستتعلم كيفية التعرف عليها، وإصلاحها، والأهم من ذلك، تجنبها في المستقبل. ستكون هذه المادة مفيدة لكل من الطلاب وأولئك الذين بدأوا للتو رحلتهم في برمجة الأنظمة.
1. تجاهل السلوك غير المحدد (UB)
من أكثر الأخطاء غدرًا هو السلوك غير المحدد (UB). لن يصدر المترجم تحذيرًا، وقد يبدو البرنامج أنه يعمل "بشكل طبيعي"، ولكن عندما تتغير التحسينات أو المنصات، سينهار كل شيء.
مثال: الوصول خارج حدود المصفوفة
int arr[5] = {1, 2, 3, 4, 5};arr[5] = 42; // UB: كتابة خارج الحدودstd::cout << arr[10]; // UB: قراءة بيانات غير مرغوب فيهاكيف تتجنب ذلك: استخدم دائمًا std::array أو std::vector مع التحقق من الحدود عبر .at()، بالإضافة إلى حاويات STL. لا تعتمد أبدًا على "الحظ" — فالسلوك غير المحدد يمكن أن يظهر في أسوأ لحظة ممكنة.
2. تسرب الذاكرة والمؤشرات الخام
لا تحتوي لغة C++ على جامع قمامة. كل new يجب أن يقابله delete. غالبًا ما ينسى المبتدئون تحرير الذاكرة، خاصةً عند حدوث استثناءات.
مثال على تسرب الذاكرة
void leak() { int* p = new int(100); // تم نسيان delete p; // يتم فقدان الذاكرة عند خروج الدالة}الحل: استخدم المؤشرات الذكية: std::unique_ptr للملكية الحصرية و std::shared_ptr للملكية المشتركة. ستقوم تلقائيًا بتحرير الذاكرة عند خروجها من النطاق.
void no_leak() { auto p = std::make_unique<int>(100); // يتم استدعاء delete تلقائيًا}3. الاستخدام غير الصحيح للمراجع والمؤشرات
الخلط بين المراجع (&) والمؤشرات (*) هو مشكلة شائعة.
- المرجع هو اسم مستعار. لا يمكن أن يكون
nullptrولا يمكن إعادة تعيينه. - المؤشر يمكن أن يكون فارغًا ويمكن أن يشير إلى كائنات مختلفة.
خطأ نموذجي: إرجاع مرجع إلى كائن محلي
int& bad_ref() { int x = 10; return x; // يتم تدمير x بعد الخروج}// الاستخدام: int& r = bad_ref(); // مرجع معلقالقاعدة: لا تقم أبدًا بإرجاع مراجع أو مؤشرات إلى متغيرات محلية. قم فقط بإرجاع البيانات التي يكون عمرها مضمونًا (مثل الوسائط التي تم تمريرها كمرجع أو المتغيرات الثابتة).
4. إهمال RAII (اكتساب الموارد هو التهيئة)
RAII هو أسلوب أساسي في لغة C++. يتم اكتساب المورد (ذاكرة، ملف، كائن مزامنة) في المنشئ ويتم تحريره في المدمر. غالبًا ما يكتب المبتدئون إدارة يدوية، مما يؤدي إلى تسرب عند حدوث استثناءات.
مثال سيء
void handle_file() { FILE* f = fopen("data.txt", "r"); // ... العمل مع الملف ... if (some_error) { return; // تم نسيان fclose! } fclose(f);}مثال جيد باستخدام RAII
void handle_file_safe() { std::ifstream f("data.txt"); if (!f) return; // ... العمل ... // يتم إغلاق الملف تلقائيًا عند الخروج من النطاق}الاستنتاج: قم دائمًا بتغليف الموارد في أغلفة RAII. للملفات — std::fstream، للذاكرة — المؤشرات الذكية، لكائنات المزامنة — std::lock_guard.
5. إهمال const و constexpr
العديد من المبتدئين لا يستخدمون