تحذير! خطأ خطير في تطبيق C ++ std :: map :: merge و std :: set :: merge في Visual Studio 2017

إذا كنت تستخدم معيار C ++ 17 في برنامج MS Visual Studio 2017 - كن حذراً: يحتوي الإصدار الحالي على خطأ حرج في تنفيذ std :: map :: merge و std :: set :: merge. التفاصيل - تحت الخفض.

كيف يظهر خطأ؟


  1. إن تعقيد std :: map :: merge و std :: set :: merge بدلاً من N * log القياسي (size () + N)) ، حيث N هو حجم الجزء المُضاف ، يتحول إلى N مربع.
  2. إذا تمت إضافة حاوية تحتوي على عدد كبير بما يكفي من العناصر بمساعدة الدمج ، فحين يتم تدمير الحاوية الناتجة ، يمكننا تجاوز سعة المكدس.
  3. تأتي الحاوية إلى حالة غير صحيحة بعد تشغيل الدمج ، بحيث تكون المظاهر الأخرى ممكنة.

ماذا تقول مايكروسوفت؟


تم إرسال bugreport بواسطتي إلى Microsoft قبل شهرين تقريبًا.
في Visual Studio 2019 ، يجب أن يكون قد تم إصلاح 2 معاينة 2.

ولكن في الإصدار الحالي من Visual Studio 2017 15.9.12 لم يتم إصلاحه حتى الآن ، واستناداً إلى آخر التقارير ، انتظر وقتًا طويلاً ...

الخطأ هو علامة اللون غير الصحيحة للعقد المضافة في تطبيق خشب الأبنوس الأحمر.

كيف تتكاثر؟


//#include "pch.h" #include <chrono> #include <string> #include <iostream> #include <map> #include <set> const size_t mainSize = 50'000; const size_t additionSize = mainSize; auto getMainMap() { std::map<size_t, std::string> result; while( result.size() < mainSize ) result.emplace(result.size(), "SomeText"); return result; } auto getAdditionMap() { std::map<size_t, std::string> result; while ( result.size() < additionSize ) result.emplace(mainSize + result.size(), "SomeAdditionText"); return result; } int main() { { auto mainMap = getMainMap(); auto addition = getAdditionMap(); auto start = std::chrono::steady_clock::now(); for ( auto const &elem : addition ) mainMap.emplace(elem); auto end = std::chrono::steady_clock::now(); std::cout << "manual insertion with copy: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << std::endl; } { auto mainMap = getMainMap(); auto addition = getAdditionMap(); auto start = std::chrono::steady_clock::now(); mainMap.merge(addition); auto end = std::chrono::steady_clock::now(); std::cout << "std::map::merge: " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << std::endl; } // <---- and stack overflow here because of incorrect mainMap after merge return 0; } 

مع اختلاف قيمة mainSize ، يمكنك الحصول على نتائج مختلفة - إما فقط التنفيذ البطيء ، أو التعطل أيضًا.

ما يجب القيام به


قم بمراجعة الكود الخاص بك واستبدال مكالمات الدمج بالإدخال اليدوي. أو الترقية إلى VS 2019.
وإذا كانت التعليمات البرمجية المترجمة قد ذهبت بالفعل إلى العميل ... Ohhh ...

Source: https://habr.com/ru/post/ar455632/


All Articles