سؤال

قبل ساعات قليلة ، كنت أتعامل مع مشكلة تسرب الذاكرة واتضح أنني حصلت حقًا على بعض الأشياء الأساسية حول الخاطئين المدمرين الافتراضيين! اسمحوا لي أن أشرح تصميمي الصفي.

class Base
{
  virtual push_elements()
  {}
};

class Derived:public Base
{
vector<int> x;
public:
   void push_elements(){ 
      for(int i=0;i <5;i++)
         x.push_back(i); 
   }
};

void main()
{
    Base* b = new Derived();
    b->push_elements();
    delete b;
}

أبلغت أداة Checker Bounds عن تسرب الذاكرة في متجه الفئة المشتق. ووجدت أن المدمر ليس افتراضيًا وأن المدمر الطبقي المشتق لا يطلق عليه. وقد تم إصلاحه بشكل مدهش عندما جعلت Destructor Virtual. أليس المتجول المعامل تلقائيًا حتى لو لم يتم استدعاء المدمرة المشتقة؟ هل هذا غريب في أداة Boundschecker أم أن فهمي للمدمر الظاهري خاطئ؟

هل كانت مفيدة؟

المحلول

حذف كائن من الفئة المشتقة من خلال مؤشر من الدرجة الأساسية عندما لا يكون للفئة الأساسية المدمرة الافتراضية إلى سلوك غير محدد.

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

نصائح أخرى

إذا لم يكن لدى الفئة الأساسية مدمرة افتراضية ، فإن نتيجة الكود الخاص بك هي سلوك غير محدد ، وليس بالضرورة المدمر الخاطئ الذي يتم استدعاؤه. هذا هو ما يفترض أن Boundschecker تشخيص.

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

السبب في حدوث ذلك هو السبب نفسه الذي سيتم استدعاء وظيفة "الخطأ" عندما تحاول تجاوز وظيفة عضو غير قميص وتسميتها من خلال مؤشر أساسي.

إذا لم يكن المدمر افتراضيًا ، فسيتم استدعاء المدمرة الأساسية. ينظف المدمر الأساسي الكائن الأساسي ويشتهي. لا توجد وسيلة لكائن الكائن الأساسي لمعرفة الكائن المشتق ، يجب أن يكون المدمر المشتق الذي يسمى ، والطريقة للقيام بذلك ، كما هو الحال مع أي وظيفة ، هي جعل المدمر افتراضيًا.

من Faq Lite C ++: "متى يجب أن يكون المدمر الخاص بي افتراضيًا؟" اقرأها هنا. (C ++ faQ Lite هو مصدر ممتاز لجميع أسئلتك المتعلقة بـ C ++ ، بالمناسبة).

في C ++ ، أ المدمرة التافهة هو مفهوم محدد بشكل متكرر - إنه مدمر كتبه المترجم لك عندما يكون لكل عضو في الفصل (وكل فئة أساسية) مدمرة تافهة. (هناك مفهوم مماثل يسمى المُنشئ التافهة.)

عندما يتم تضمين كائن مع مدمرة غير تافهة في كائن (مثل vector في مثالك) ، ثم مدمر الكائن الخارجي (مثل الخاص بك Derived) في لم يعد تافهة. على الرغم من أنك لم تكتب Destructor ، إلا أن برنامج التحويل البرمجي C ++ كتب تلقائيًا مدمرًا يطلق على المدمرات لأي أعضاء لديهم تدمير.

لذلك ، على الرغم من أنك لم تكتب أي شيء ، إلا أن تحذيرات كتابة مدمرة غير قادة لا تزال تقدمًا.

إذا كنت قادمًا من C#، فأنت على صواب في التساؤل عن سبب عدم التخلص من المتجه تلقائيًا. ولكن في C ++ ، لا تتوفر إدارة الذاكرة التلقائية إلا إذا كنت تستخدم Microsoft Manged Extesions إلى C ++ (C ++/CLI).

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

Destructor هي وظيفة العضو في الفصل الذي اسمه نفس اسم اسم الفصل ويسببه علامة Tilde (~). يتم استخدام Destructor لتدمير كائن الفصل عندما يخرج الكائن عن النطاق أو يمكنك القول أن كل تنظيف التدمير الطبقي يجب أن يتم في Destructor. يتم تخصيص جميع الذاكرة أثناء بناء الكائن في الفصل (أو إطلاق الذاكرة) عندما ينفد الكائن عن النطاق.

ابحث عن المزيد من التفاصيل مع مثال على BODESCHECK

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top