تعمل الحاويات الترابطية C ++ مع نوع مفتاح معين. للبحث عنها باستخدام مفتاح من هذا النوع ( std :: string ، std :: string_view ، const char * ) ، يمكن أن نتحمل خسائر كبيرة في الأداء. في هذه المقالة ، سأوضح لك كيفية تجنب ذلك باستخدام ميزة بحث غير متجانسة تمت إضافتها مؤخرًا.
وجود حاوية std :: map <std :: string، int> يجب أن يتم إعلامنا بالتكلفة العالية المحتملة عند البحث (وبعض العمليات الأخرى باستخدام مفتاح كمعامل ) عليها بأسلوب c.find ("hello world") . الحقيقة هي أن كل هذه العمليات تتطلب افتراضيًا مفتاحًا من النوع المطلوب ، وفي حالتنا يكون هو std :: string . نتيجة لذلك ، عند استدعاء find ، نحتاج إلى إنشاء مفتاح من النوع std :: string ضمنيًا من const char * ، مما سيكلفنا في أحسن الأحوال memcpy إضافية (إذا كان تطبيق المكتبة القياسي الخاص بنا يحتوي على "تحسين سلسلة صغيرة" والمفتاح قصير) ، و أيضا strlen اضافية(ما لم يخمن المترجم أو ليس لديه طريقة لحساب طول السطر في وقت الترجمة). في أسوأ الحالات ، سيتعين عليك الدفع بالكامل: من خلال تخصيص الذاكرة وتحريرها من الكومة لمفتاح مؤقت في مكان يبدو مسطحًا ، وقد يكون هذا بالفعل مشابهًا لوقت البحث نفسه.
يمكننا تجنب العمل غير الضروري مع البحث غير المتجانس. تم إضافة وظائف لتشغيلها الصحيحة للحاويات أمر ( مجموعة ، مولتيست ، خريطة ، multimap ) في جميع أماكن مماثلة منذ C ++ 14 مستوى وغير مرتبة حاويات ( unordered_set ، unordered_multiset ، unordered_map ، unordered_multimap ) منذ C ++ 20.
// C++14
iterator find(const Key& key);
const_iterator find(const Key& key) const;
// C++14
template < class K > iterator find(const K& x);
template < class K > const_iterator find(const K& x) const;
ولكن ، كما هو الحال دائمًا ، في C ++ ، هناك مشكلة في هذا المكان ، واسمه هو المقارنة الافتراضية. المقارن الافتراضي لـ std :: map <std :: string، int> هو std :: less <std :: string> الذي تم إعلان وظيفة المقارنة الخاصة به على النحو التالي:
// T , .. std::string
bool operator()(const T& lhs, const T& rhs) const;
لا يمكن استخدامه لمقارنتنا غير المتجانسة ، لأنه لا يزال لديه نفس المشاكل (تحتاج إلى إنشاء نوع معين من المفاتيح). يأتي التخصص std :: less <void> للإنقاذ ، وهو خالي من هذه المشاكل.
template <>
struct less<void> {
using is_transparent = void;
template < class T, class U >
bool operator()(T&& t, U&& u) const {
return std::forward<T>(t) < std::forward<U>(u);
}
};
شيء من هذا القبيل يبدو مثل هذا التخصص، فاتني نقطة معconstexprوnoexceptالبساطة من الوصف.
في علامة is_transparent يقول الحاويات التي هذه المقارنة هي قادرة على المقارنة غير المتجانسة والتي وظائف البحث غير المتجانسة الجديدة تصبح متاحة على ذلك.
, operator<(const std::string&, const char*) :
std::map<std::string, int, std::less<>> c;
c.find("hello world");
, , , operator< . - , , std::thread std::set std::thread::id.
struct thread_compare {
using is_transparent = void;
bool operator()(const std::thread& a, const std::thread& b) const {
return a.get_id() < b.get_id();
}
bool operator()(const std::thread& a, std::thread::id b) const {
return a.get_id() < b;
}
bool operator()(std::thread::id a, const std::thread& b) const {
return a < b.get_id();
}
};
//
std::set<std::thread, thread_compare> threads;
// id
threads.find(std::this_thread::get_id());
حسنًا ، لا تنس أن هذا لا يتعلق فقط بالوظيفة find. فقط هذه المخاوف وظائف: count، equal_range، lower_bound، upper_boundو contains.
بحث غير متجانس سعيد ، عزيزي القارئ!