مقدمة: لماذا تتحول مراجعتك إلى ساحة معركة؟
لقد أرسلت طلب دمج (Merge Request). يبدو كل شيء نظيفًا، المنطق صحيح، الكود يترجم. بعد ساعة، يأتي رد من المطور الكبير: «-10 نقاط لجريفندور» و35 تعليقًا على 200 سطر من الكود. هل هذا مألوف؟
مراجعة كود C++ ليست مجرد فحص للصياغة. إنها فن يفصل بين المبتدئين وكبار المطورين. تمنح C++ المطور سلطة هائلة على الذاكرة والأداء، لكن مع القوة العظيمة تأتي مسؤولية كبيرة تجاه السلوك غير المحدد وتسرب الموارد.
في هذه المقالة، سنلقي نظرة داخل عقل المراجع المتمرس. لقد جمعت ملاحظات حقيقية يتركها كبار المطورين على مراجعات الكود في مشاريع الإنتاج. إذا كنت تكتب بلغة C++ وتريد قبول طلبات الدمج الخاصة بك من المرة الأولى - اقرأ بعناية. وإذا كنت قائد فريق - استخدم قائمة التحقق هذه لتأهيل المبتدئين.
1. إطلاق النار على القدم: إدارة الذاكرة اليدوية
أكثر جدل متكرر في المراجعة - "لماذا لا تستخدم المؤشرات الذكية؟". يكره كبار المطورين استخدام new و delete الخام في C++ الحديثة (C++11 وما أحدث).
مثال سيء
class DataProcessor {
int* buffer;
size_t size;
public:
DataProcessor(size_t s) : size(s) {
buffer = new int[s]; // من سيقوم بالحذف؟
}
~DataProcessor() {
delete[] buffer; // ماذا لو حدث استثناء في المُنشئ؟
}
};
تعليق المطور الكبير: "انتهاك RAII. إذا ألقى المُنشئ استثناءً بعد تخصيص الذاكرة - لن يتم استدعاء المُدمّر. تسرب للذاكرة. استخدم std::vector أو std::unique_ptr."
مثال صحيح
class DataProcessor {
std::vector<int> buffer;
public:
explicit DataProcessor(size_t s) : buffer(s) {}
};
كبار المطورين يعشقون RAII (اكتساب الموارد هو تهيئة). إذا كتبت new في الكود، كن مستعدًا لشرح لماذا std::make_unique أو std::vector لا يناسبك. في 95% من الحالات - هي مناسبة.
2. Const-correctness: ضع لنفسك "فاصلة"
إغفال const هو بمثابة قطعة قماش حمراء لأي مطور كبير في C++. هذا ليس مجرد أسلوب، بل هو عقد مع قارئ الكود والمُجمّع.
ما يثير الغضب في المراجعة
std::string getName() { // لماذا ليس const؟
return name;
}
void printData(std::vector<int>& data) { // نسخة؟ مرجع؟ يُغير؟
for (auto& item : data) {
std::cout << item;
}
}
تعليق المطور الكبير: "الطريقة getName() لا تُغير الكائن - اجعلها const. المعامل data لا يتغير - مرره كـ const std::vector<int>&. وإلا فإن الكود المستدعي لا يعرف هل ستغير بياناته أم لا."
نُصحح
std::string getName() const { // طريقة const
return name;
}
void printData(const std::vector<int>& data) { // مرجع const
for (const auto& item : data) {
std::cout << item;
}
}
القاعدة بسيطة: إذا كانت الطريقة لا تُغير حالة الكائن - const. إذا كانت الدالة لا تُغير الوسيط - const T&. Const correctness في C++ ليست خيارًا، بل هي معيار.
3. Move-семантика: النسخ ليس ديننا
C++ الحديثة تدور حول النقل، وليس النسخ. يرى كبار المطورين فورًا أين تقوم بإنشاء نسخ زائدة وتقتل الأداء.
نمط سيء
std::vector<int> processData(std::vector<int> data) { // نسخة عند الإدخال
// ... الكثير من المنطق ...
return data; // نسخة عند الإخراج؟ أم NRVO؟
}
void caller() {
std::vector<int> bigData = {1, 2, 3, ... 1000000};
auto result = processData(bigData); // نسخة أخرى!
}
تعليق