تكرار std::map - اختلافات الترتيب بين إصدارات Debug وRelease

StackOverflow https://stackoverflow.com/questions/137258

  •  02-07-2019
  •  | 
  •  

سؤال

إليك نمط التعليمات البرمجية الشائع الذي يجب أن أعمل معه:

class foo {
public:
    void InitMap();
    void InvokeMethodsInMap();
    static void abcMethod();
    static void defMethod();
private:
    typedef std::map<const char*, pMethod> TMyMap;
    TMyMap m_MyMap;
}

void
foo::InitMap()
{
    m_MyMap["abc"] = &foo::abcMethod;
    m_MyMap["def"] = &foo::defMethod;
}

void
foo::InvokeMethodsInMap()
{
    for (TMyMap::const_iterator it = m_MyMap.begin();
        it != m_MyMap.end(); it++)
    {
        (*it->second)(it->first);
    }
}

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

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

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

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

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

المحلول

لا تستخدم const char* كمفتاح للخرائط.وهذا يعني أن الخريطة مرتبة حسب عناوين السلاسل، وليس محتويات السلاسل.إستخدم std::string كنوع المفتاح، بدلاً من ذلك.

std::map ليس جدول تجزئة، وعادةً ما يتم تنفيذه كشجرة ذات لون أحمر وأسود، ويتم ضمان ترتيب العناصر وفقًا لبعض المعايير (افتراضيًا، < مقارنة بين المفاتيح).

نصائح أخرى

تعريف الخريطة هو:
خريطة<المفتاح، البيانات، المقارنة، التخصيص>

حيث تكون آخر معلمتين للقالب افتراضية أيضًا:
يقارن:أقل<مفتاح>
تخصيص:المخصص<value_type>

عند إدراج قيم جديدة في الخريطة.تتم مقارنة القيمة الجديدة (valueToInsert) بالقيم القديمة بالترتيب (ملحوظة: هذا ليس بحثًا تسلسليًا، ويضمن المعيار الحد الأقصى لتعقيد الإدخال لـ O(log(N)) ) حتى تُرجع Compare(value,ValueToInsert) صحيحًا.لأنك تستخدم "حرف ثابت*" كالمفتاح.يستخدم كائن المقارنة أقل<const شار*> هذه الفئة تقوم فقط بعمل < على القيمتين.لذا فأنت في الواقع تقوم بمقارنة قيم المؤشر (وليس السلسلة) وبالتالي فإن الترتيب عشوائي (حيث أنك لا تعرف أين سيضع المترجم السلاسل.

هناك نوعان من الحلول الممكنة:

  • قم بتغيير نوع المفتاح بحيث يقوم بمقارنة قيم السلسلة.
  • حدد نوع مقارنة آخر يقوم بما تحتاجه.

أنا شخصياً (مثل كريس) سأستخدم فقط std::string لأن عامل التشغيل < المستخدم في السلاسل يُرجع مقارنة بناءً على محتوى السلسلة.ولكن من أجل الحجج يمكننا فقط تحديد نوع المقارنة.

struct StringLess
{
    bool operator()(const char* const& left,const char* const& right) const
    {
        return strcmp(left,right) < 0;
    }
};

///

typedef std::map<const char*, int,StringLess> TMyMap;

إذا كنت تريد استخدام const char * كمفتاح لخريطتك، فقم أيضًا بتعيين وظيفة مقارنة المفاتيح التي تستخدم strcmp (أو ما شابه) لمقارنة المفاتيح.بهذه الطريقة سيتم ترتيب خريطتك حسب محتويات السلسلة، بدلاً من قيمة مؤشر السلسلة (أي.الموقع في الذاكرة).

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