كيف حذف C++-إنه يحذف الكائنات الخاصة بي ولكن لا يزال بإمكاني الوصول إلى البيانات؟




لا استطيع الدخول الى حسابي في الفيس بوك (11)

لقد كتبت لعبة tetris بسيطة وعملية مع كل كتلة كمثال على فئة فردية.

class SingleBlock
{
    public:
    SingleBlock(int, int);
    ~SingleBlock();

    int x;
    int y;
    SingleBlock *next;
};

class MultiBlock
{
    public:
    MultiBlock(int, int);

    SingleBlock *c, *d, *e, *f;
};

SingleBlock::SingleBlock(int a, int b)
{
    x = a;
    y = b;
}

SingleBlock::~SingleBlock()
{
    x = 222;
}

MultiBlock::MultiBlock(int a, int b)
{
    c = new SingleBlock (a,b);
    d = c->next = new SingleBlock (a+10,b);
    e = d->next = new SingleBlock (a+20,b);
    f = e->next = new SingleBlock (a+30,b);
}

لدي وظيفة تقوم بمسح لخط كامل ، وتعمل من خلال قائمة من الكتل المرتبطة بحذف تلك ذات الصلة وإعادة تعيين -> المؤشرات التالية.

SingleBlock *deleteBlock;
SingleBlock *tempBlock;

tempBlock = deleteBlock->next;
delete deleteBlock;

اللعبة تعمل ، يتم حذف كتل بشكل صحيح ويعمل كل شيء كما هو من المفترض أن. ومع ذلك ، لا يزال بإمكاني الوصول إلى وحدات بت عشوائية من البيانات المحذوفة.

إذا قمت بطباعة كل من القيم المفردة المحذوفة "x" بعد حذفها ، فإن بعضها يعيد قمامة عشوائية (تؤكد الحذف) ويعود بعضها إلى 222 ، ويقول لي على الرغم من أن المدمر كان يسمى بالبيانات لم يتم حذفها فعليًا من الكومة. تظهر العديد من التجارب المماثلة أنه دائمًا نفس الكتل المحددة التي لا يتم حذفها بشكل صحيح.

النتائج:

Existing Blocks:
Block: 00E927A8
Block: 00E94290
Block: 00E942B0
Block: 00E942D0
Block: 00E942F0
Block: 00E94500
Block: 00E94520
Block: 00E94540
Block: 00E94560
Block: 00E945B0
Block: 00E945D0
Block: 00E945F0
Block: 00E94610
Block: 00E94660
Block: 00E94680
Block: 00E946A0

Deleting Blocks:
Deleting ... 00E942B0, X = 15288000
Deleting ... 00E942D0, X = 15286960
Deleting ... 00E94520, X = 15286992
Deleting ... 00E94540, X = 15270296
Deleting ... 00E94560, X = 222
Deleting ... 00E945D0, X = 15270296
Deleting ... 00E945F0, X = 222
Deleting ... 00E94610, X = 222
Deleting ... 00E94660, X = 15270296
Deleting ... 00E94680, X = 222

هل القدرة على الوصول إلى البيانات من وراء القبر المتوقع؟

آسف إذا كان هذا هو لف لفترة طويلة قليلا.


Answer #1

نعم ، يمكن توقع ذلك في بعض الأحيان. في حين أن المساحة الاحتياطية new للبيانات ، delete ببساطة إبطال المؤشر الذي تم إنشاؤه بالآخر ، مما يسمح بكتابة البيانات في المواقع المحجوزة مسبقاً ؛ لا يحذف بالضرورة البيانات. ومع ذلك ، يجب ألا تعتمد على هذا السلوك نظرًا لأن البيانات في تلك المواقع قد تتغير في أي وقت ، ومن المحتمل أن يتسبب ذلك في سوء تصرف برنامجك. هذا هو السبب بعد استخدام delete على مؤشر (أو delete[] على صفيف تم تخصيصه بـ new[] ، يجب تعيين NULL إليه بحيث لا يمكنك العبث بمؤشر غير صالح ، على افتراض أنك لن تخصص الذاكرة باستخدام new أو new[] قبل استخدام هذا المؤشر مرة أخرى.


Answer #2

لا يقوم النظام بإلغاء تحديد الذاكرة عند تحريرها عبر delete() . وبالتالي ، تظل المحتويات قابلة للوصول حتى يتم تخصيص الذاكرة لإعادة استخدامها والكتابة فوقها.


Answer #3

سيؤدي ذلك إلى سلوك غير محدد وحذف إلغاء تخصيص الذاكرة ، ولا يعيد تهيئته بصفر.

إذا كنت ترغب في جعله صفرًا ، فافعل ما يلي:

SingleBlock::~SingleBlock()

{    x = y = 0 ; }

Answer #4

هل القدرة على الوصول إلى البيانات من وراء القبر المتوقع؟

هذا معروف تقنيًا باسم سلوك غير محدد. لا تتفاجأ إذا كان يوفر لك علبة من البيرة سواء.


Answer #5

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

أوصي بأنك إذا قمت بكتابة الكود مع مؤشرات new / delete و raw (بدلاً من std::make_shared() وما شابه ذلك) ، فإنك تمارس اختبارات الوحدة الخاصة بك تحت Valgrind على الأقل لديها فرصة اكتشاف مثل هذه الأخطاء.


Answer #6

هذا هو ما يستدعي C ++ سلوكًا غير معروف - قد تتمكن من الوصول إلى البيانات ، قد لا تفعل ذلك. على أي حال ، من الخطأ القيام به.


Answer #7

لن يتغير / يغير الذاكرة بعد ... ولكن في مرحلة ما ، سوف يتم سحب البساط من تحت قدميك.

لا من المؤكد أنه لا يمكن التنبؤ به: يعتمد ذلك على مدى سرعة خزن تخصيص / إلغاء تخصيص الذاكرة.


Answer #8

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

عندما ينتهي الفصل الدراسي وأنت على وشك مغادرة الغرفة ، لا توجد سياسة تتطلب منك مسح السبورة - يمكنك ببساطة تسليم السبورة للمعلم التالي الذي سيكون قادرًا بوجه عام على رؤية ما كتبته.


Answer #9

هل القدرة على الوصول إلى البيانات من وراء القبر المتوقع؟

في معظم الحالات ، نعم. استدعاء حذف لا الصفر الذاكرة.

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

إذا كنت تفكر في الأمر ، فمن المنطقي - عندما تخبر المترجم أنك لم تعد مهتمًا بالذاكرة (باستخدام الحذف ) ، فلماذا يقضي الكمبيوتر وقتًا في تقليله.


Answer #10

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


Answer #11

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

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





c++-faq