C++ / دليل حلول تحريري

إصلاح المراجع المتدلية والاستخدام بعد التحرير

اعثر على مالك المؤشر أو المرجع أو العرض، ثم أعد تصميم علاقة العمر بدل الاعتماد على نص بقي مصادفة في تخزين ميت.

وقت القراءة التقريبي: 3 دقيقةتاريخ مراجعة المحتوى

قاعدة معرفة للقراءة فقط · بلا تعليقات عامة

تعرّف على الأعراض

قد يبدو المرجع سليمًا في بناء ويفشل بعد تحسين أو تعديل بسيط. قد يبلغ تشخيص الذاكرة عن heap-use-after-free أو stack-use-after-return أو خطأ عمر آخر حسب الحالة وأدوات الفحص. تصنّف هذه الأسماء الوصول ولا تتنبأ بصورة محمولة بسلوك الشيفرة غير الصالحة.

قد تصاحب السلوك غير المعرّف نصوص قديمة أو تعطل أو نتائج تبدو صحيحة. لا تشغّل مثالًا متدليًا متعمدًا لمعرفة ناتجه المتوقع. افحص إنشاء الكائن الأساسي وملكيته وإتلافه واستخدامه اللاحق بدلًا من ذلك.

افهم الأسباب المحتملة

  • تستعير المراجع والمؤشرات الخام وstring_view وspan التخزين عادة ولا تملك عمره. قد تنهي إعادة مرجع إلى محلي أو حفظ عرض لمؤقت أو إتلاف مالك ذكي أو إعادة تخصيص حاوية صلاحية الاستعارة. لا تحول const البيانات المستعارة إلى مملوكة.
  • قد يحتفظ رد نداء مخزن بالتقاط مرجعي بعد انتهاء نطاق إنشائه. وليس إنشاء shared_ptr مستقل من عنوان خام إصلاحًا صالحًا، لأنه ينشئ كتلة ملكية أخرى وقد يسبب حذفًا مزدوجًا. يجب تأسيس الملكية ونقلها باتساق.

تتبّع المالك وآخر وصول صالح

دوّن الكائن الذي يملك البايتات والحدث الدقيق الذي يتلفها أو ينقلها. يعيد المقتطف المكسور عمدًا مرجعًا يموت مالكه المحلي عند العودة. هو غير قابل للتشغيل ولا يملك إخراجًا معرّفًا. لا تمدد قابلية قراءة العنوان في المنقّح عمر الكائن. راجع المستدعين أيضًا، خاصة من يخزنون المرجع أو يلفونه في عرض.

cpp مقتطف ذو عمر غير صالح عمدًا
#include <string>
const std::string& broken_label() {
    const std::string local{"report"};
    return local;
}

لا تنفّذ هذه الدالة. يتدلى المرجع المعاد بعد إتلاف local، ولا يُنسب إليها إخراج.

إعادة قيمة للبيانات المنشأة حديثًا

أعد std::string بالقيمة عندما تنشئ الدالة سلسلة جديدة. يملك المستدعي النتيجة مستقلًا، وقد تتيح إزالة النسخ أو النقل انتقالًا فعالًا. صحة الملكية سبب التغيير؛ فلا تُعد مرجعًا محليًا لتحسين تخميني. ينشئ البرنامج المصحح نتيجة تبقى حية حتى الطباعة ثم تتحرر تلقائيًا.

cpp نتيجة يملكها المستدعي
#include <iostream>
#include <string>
std::string label() { return std::string{"report"}; }
int main() {
    const std::string owned = label();
    std::cout << owned << "\n";
}
الناتج المتوقع
report

تملك owned عمرًا خاصًا داخل main، ولا تكشف الدالة مرجعًا إلى محلي مدمر.

إصلاح العلاقة عند الحدود غير المتزامنة

لردود النداء المنتظرة التقط قيمة مملوكة أو مالكًا مشتركًا صريحًا إذا وجب الاحتفاظ بالمورد. استخدم weak_ptr مع lock مفحوصة إذا سمح العمل بانتهاء العمر. ولعناصر الحاويات أعد الوصول بعد التعديل البنيوي أو احفظ معرّفًا منطقيًا ثابتًا. لا تضف ملكية مشتركة في كل مكان؛ فكثيرًا ما يزيل نطاق أبسط أو إرجاع بالقيمة الاعتماد كاملًا.

تحقق من نجاح الإصلاح

ترجم وشغّل البرنامج المصحح المكتمل فقط؛ يطبع report ثم سطرًا جديدًا. أضف اختبارات تستخدم القيم بعد خروج الدالة المنشئة وتتلف المالكين الأصليين قبل تشغيل المراقبين الاختياريين.

شغّل المسارات المصححة بـAddressSanitizer في بناء مخصص على أدوات مدعومة. أبقِ مراجعة الملكية حتى بعد تشغيل سليم؛ فالتشخيص يفحص المسارات المنفذة وقد لا يكشف كل وصول متدلٍ. لا يلزم تنفيذ أي مثال غير معرّف في الدليل.

امنع تكرار المشكلة

  • وثّق مالك كل مؤشر أو مرجع أو عرض يغادر الاستدعاء وشروط إبطاله. فضّل نتائج مالكة وأعضاء RAII والتقاطات صريحة ونطاق استعارة قصيرًا. عامل الثبات والعمر خاصيتين منفصلتين.

المراجع الرسمية