سؤال

لذلك أنا أصنع لعبة ثعبان مع النقل الفضائي والفئران المعتادة. كان لدي حلقة تعمل مثل هذا:

while(snake.alive() && miceEaten < micePerLevel)
{
    displayInfo(lives, score, level, micePerLevel - miceEaten);
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
}

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

while(snake.alive() && miceEaten < micePerLevel)
{
    //some code
    if(miceEaten())
    {
        //update score...
    }
    //more stuff...
    displayInfo(lives, score, level, micePerLevel - miceEaten);
}

وتتوقف عن بعد عن العمل! تعطل البرنامج كلما وصلت الثعبان إلى النقل الفضائي. و displayInfo يستخدم الرمز التالي:

stringstream s;
s << "LEVEL " << left << setw(12) << level << "LIVES: " << setw(12) << lives << "MICE LEFT: " << setw(12) << miceLeft
    << "SCORE: " << setw(13) << score;
printLine(0, s.str(), WHITEONBLUE);

أين printLine فقط لديه color_set, mvprintw, ، و refresh(). لا علاقة له مع النقل الفضائي. عجيب.

لذلك ذهبت إلى وظيفة الأفعى حيث تحصل الأفعى على موقعها التالي من النقل الفضائي:

    body.push_back(teleports[overlap(next)]->teleportFrom(dir)); //next is a Location object

أين teleports[overlap(next)]->teleportFrom(dir) إرجاع الموقع الذي سيتم نقله عن الأفعى. في محاولة لمعرفة سبب تعطلها (ربما Teleport هل أعيد بعض الموقع خارج الشاشة؟) ، أضفت الأسطر الثلاثة التالية قبل السطر أعلاه:

    Location l = teleports[overlap(next)]->teleportFrom(dir);
    mvprintw(1, 0, "(%i, %i)", l.x, l.y);
    refresh();

وتختفي المشكلة!

ليس ذلك فحسب ، ولكن يجب أن يكون لدي هذه الخطوط الثلاثة. إذا علقت mvprintw(1, 0, "(%i, %i)", l.x, l.y);, ، أو refresh();, ، أو كليهما ، يتعطل البرنامج كما كان من قبل عند الوصول إلى النقل الفضائي.

أي أفكار حول ما قد يسبب هذا السلوك؟

تحديث: حاولت إزالة جميع التحذيرات (التي كانت في الغالب تحذيرات حول مقارنات الأرقام الموقعة/غير الموقعة) ، ولكن لا يزال هناك واحد فقط:

warning: reference to local variable 'other' returned

والرمز:

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

ماذا أفعل لإصلاح هذا التحذير؟

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

المحلول

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

Location& Location::operator = (Location const& other)
{
    // Does it really matter if you assign to self?
    x = other.x;
    y = other.y;
    return *this;
}

بدا النسخة القياسية والمبادلة مبالغة بعض الشيء لمثل هذه الفئة البسيطة.

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

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

// notice the parameter is passed by value (i.e. a copy).
// So the copy part is aromatically taken care of here.
// So now you just need tom implement the swap() part of the idiom.
Location& Location::operator = (Location other)
{
    this->swap(other);
    return *this;
}

void Location::swap(Location& other)
{
    std::swap(x, other.x);
    std::swap(y, other.y);
}

نصائح أخرى

Location& Location::operator = (Location other)
{
    if(this == &other)
        return other;
    x = other.x;
    y = other.y;
    return *this;
}

هذا يعيد إشارة. عندما تعود الوظيفة ، ماذا يحدث other؟ (يموت ، وأنت تشير إلى لا شيء.) نظرًا لأن هذا هو الفصل الذي تتعامل معه حول منطقة المشكلة ، فربما يكون هذا هو السبب. يترك إعادة ترتيب الكود المحيط المكدس في حالة معينة حيث الإشارة إلى المتغير الميت "يعمل".

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

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

هل راجعت الرمز الذي يسبب هذا الشذوذ؟ ال Heisenbug الظواهر المقتبسة هنا:

أحد الأمثلة الشائعة هو وجود خطأ يحدث في برنامج تم تجميعه باستخدام برنامج التحويل البرمجي تحسين ، ولكن ليس في نفس البرنامج عند تجميعه دون تحسين (على سبيل المثال ، لإنشاء إصدار وضع تصحيح)

فيما يلي بعض الإرشادات:

  • حالة السباق؟ هل تستخدم المواضيع؟
  • المؤشر فوق الحدود في مكان ما؟
  • قم بتشغيل الكود الخاص بك من خلال فالغريند لمراقبة أي تغييرات غير عادية/غير منتظمة في مخازن الذاكرة في مكان ما

اقتباس آخر:

أحد الأسباب الشائعة لسلوك HeisenBug هو أن تنفيذ برنامج في وضع التصحيح غالبًا ما ينظف الذاكرة قبل بدء البرنامج ، ويجبر المتغيرات على مواقع المكدس ، بدلاً من الاحتفاظ بها في السجلات. يمكن أن تغير هذه الاختلافات في التنفيذ تأثير الأخطاء التي تنطوي على وصول الأعضاء خارج الحدود أو الافتراضات غير الصحيحة حول المحتويات الأولية للذاكرة. سبب آخر يتمثل في توفير الساعات أو واجهات المستخدم الأخرى التي تتسبب في تنفيذ رمز إضافي (مثل ملحقات الممتلكات) ، والتي يمكن ، بدورها تغيير حالة البرنامج. سبب آخر هو fandango على القلب ، تأثير المؤشر ينفد من الحدود. في C ++ ، هناك العديد من heisenbugs ناتجة عن متغيرات غير مؤهلة.

تأكد من إيقاف تشغيل المفاتيح - لا يوجد تحسين ، معلومات تصحيح كاملة ، مسح أي بنيات موجودة ، إعادة تشغيل IDE وإعادة الترجمة مرة أخرى ....

بادئ ذي بدء ، موقعك :: المشغل = يجب أن يكون هكذا بدلاً من ذلك:

Location& Location::operator = (const Location &other)
{
    if(this == &other)
        return *this;
    x = other.x;
    y = other.y;
    return *this;
}

ومع ذلك ، ربما لا يفسر الحادث. لا تصطدم المؤشرات السيئة على المكدس هنا في معظم البنى (على افتراض x و y int).

الآن بعد ذلك ، هذا هو mandelbug ، وليس heisenbug. لديك شخص آخر في مكان ما يفسد الذاكرة. حظا طيبا وفقك الله.

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