it-swarm.asia

لماذا يكون المتجه <bool> ليس حاوية STL؟

يقول البند 18 من كتاب Scott Meyers STL الفعال: 50 طرق محددة لتحسين استخدامك لمكتبة القوالب القياسية لتفادي vector <bool> لأنها ليست حاوية STL ولا تحتوي بالفعل على سجلات.

الكود التالي:

vector <bool> v; 
bool *pb =&v[0];

لن يتم تجميعها ، مما يخالف متطلبات حاويات STL.

خطأ:

cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization

من المفترض أن يكون نوع الإرجاع vector<T>::operator [] ، ولكن لماذا تعتبر هذه الحالة خاصة بـ vector<bool>؟

ماذا تتكون vector<bool> فعلاً من؟

يقول البند كذلك:

deque<bool> v; // is a STL container and it really contains bools

هل يمكن استخدام هذا كبديل لـ vector<bool>؟

يمكن لأي شخص يرجى شرح هذا؟

79
P0W

لأسباب تحسين المساحة ، يستدعي معيار C++ (بقدر ما هو C++ 98) صراحة vector<bool> كحاوية قياسية خاصة حيث يستخدم كل منطقي مساحة بت واحدة فقط بدلاً من بايت واحد كتطبيق منطقي عادي (تطبيق نوع من "مجموعة ديناميكية"). في مقابل هذا التحسين ، لا يوفر كل إمكانات وواجهة حاوية قياسية عادية.

في هذه الحالة ، نظرًا لأنه لا يمكنك أخذ عنوان قليلاً داخل بايت ، لا يمكن لأشياء مثل operator[] إرجاع bool& ولكن بدلاً من ذلك ، يمكنك إرجاع كائن وكيل يسمح بمعالجة البت المحدد المعني. نظرًا لأن كائن الوكيل هذا ليس bool& ، فلا يمكنك تعيين عنوانه إلى bool* كما يمكنك مع نتيجة استدعاء المشغل على حاوية "عادية". وهذا بدوره يعني أن bool *pb =&v[0]; ليس رمزًا صالحًا.

من ناحية أخرى ، لا يحتوي deque على أي تخصص من هذا القبيل يتم استدعاؤه بحيث يأخذ كل منطقي بايت ويمكنك أن تأخذ عنوان قيمة الإرجاع من operator[].

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

90
Mark B

vector<bool> يحتوي على قيم منطقية في نموذج مضغوط باستخدام بت واحد فقط للقيمة (وليس 8 كيف تفعل المصفوفات bool []). لا يمكن إرجاع مرجع إلى بعض الشيء في c ++ ، لذلك هناك نوع مساعد خاص ، "مرجع بت" ، يوفر لك واجهة لبعض الشيء في الذاكرة ويسمح لك باستخدام عوامل التشغيل والقوائم القياسية.

24
Ivan Smirnov

المشكلة هي أن vector<bool> تُرجع كائن المرجع الوكيل بدلاً من مرجع حقيقي ، بحيث لن يتم تجميع كود نمط C++ 98 bool * p = &v[0];. ومع ذلك ، يمكن إجراء الحديث C++ 11 مع auto p = &v[0]; إلى ترجمة إذا operator& أيضا بإرجاع كائن مؤشر وكيل . قام Howard Hinnant بكتابةمنشور في المدونةيوضح بالتفصيل التحسينات الحسابية عند استخدام هذه المراجع والمؤشرات بالوكالة.

لدى Scott Meyers عنصر 30 طويل في أكثر فعالية C++ حول فئات الوكيل. يمكنك أن تقطع شوطًا طويلاً في تقريبًا تقليد الأنواع المضمّنة: لأي نوع محدد T ، يمكن جعل زوج من الوكلاء (مثل reference_proxy<T> و iterator_proxy<T>) متسقين بشكل متبادل ، بمعنى أن reference_proxy<T>::operator&() و iterator_proxy<T>::operator*() هما معكوس.

ومع ذلك ، في مرحلة ما يحتاج المرء إلى تعيين كائنات الوكيل مرة أخرى ليتصرف مثل T* أو T&. بالنسبة لوكلاء التكرار ، يمكن للمرء أن يفرط في operator->() والوصول إلى واجهة القالب T دون إعادة تنفيذ جميع الوظائف. ومع ذلك ، بالنسبة إلى الوكلاء المرجعيين ، ستحتاج إلى التحميل الزائد operator.() ، وهذا غير مسموح به في C++ الحالي (على الرغم من أن Sebastian Redl قدم مثل هذا الاقتراح في BoostCon 2013). يمكنك عمل حل بديل مثل عضو .get() داخل الوكيل المرجعي ، أو تطبيق كل واجهة T داخل المرجع (هذا ما يتم إجراؤه لـ vector<bool>::bit_reference) ، ولكن هذا سيفقد بناء الجملة المدمج أو يقدم تحويلات معرفة من قبل المستخدم لا تحتوي على دلالات مضمّنة لتحويلات الكتابة (يمكن أن يكون لديك على الأقل تحويل واحد محدد بواسطة المستخدم لكل وسيطة).

TL ؛ DR : لا vector<bool> ليست حاوية لأن المعيار يتطلب مرجعًا حقيقيًا ، ولكن يمكن إجراؤه ليتصرف كحاوية تقريبًا ، على الأقل أقرب بكثير مع C++ 11 (تلقائي) من في C++ 98.

20
TemplateRex

يعتبر الكثيرون أن التخصص vector<bool> خطأ.

في ورقة "إهمال أجزاء المكتبة الأثرية في C++ 17"
هناك اقتراح بـ إعادة النظر في التخصص الجزئي المتجه .

لقد كان هناك تاريخ طويل من التخصص الجزئي المنطقي لـ std :: vector الذي لا يفي بمتطلبات الحاوية ، وعلى وجه الخصوص ، لا يفي التكرارون بمتطلبات مكرر الوصول العشوائي. تم رفض محاولة سابقة لاستبعاد هذه الحاوية لـ C++ 11 ، N2204 .


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

5
Trevor Hickey

انظر كيف يتم تنفيذه. تعتمد STL بشكل كبير على القوالب وبالتالي تحتوي الرؤوس على الكود الذي تقوم به.

على سبيل المثال ، انظر إلى stdc ++ application here .

من المثير للاهتمام أيضًا على الرغم من عدم وجود ناقل بت متوافق مع stl هو llvm :: BitVector من هنا .

جوهر llvm::BitVector هو فئة متداخلة تسمى reference والحمل الزائد المشغل المناسب لجعل BitVector يتصرف على غرار vector مع بعض القيود. الكود أدناه هو واجهة مبسطة لإظهار كيف يخفي BitVector فئة تسمى reference لجعل التنفيذ الحقيقي يتصرف تقريبًا كصفيف حقيقي من bool دون استخدام بايت واحد لكل قيمة.

class BitVector {
public:
  class reference {
    reference &operator=(reference t);
    reference& operator=(bool t);
    operator bool() const;
  };
  reference operator[](unsigned Idx);
  bool operator[](unsigned Idx) const;      
};

هذا الرمز هنا لديه خصائص نيس:

BitVector b(10, false); // size 10, default false
BitVector::reference &x = b[5]; // that's what really happens
bool y = b[5]; // implicitly converted to bool 
assert(b[5] == false); // converted to bool
assert(b[6] == b[7]); // bool operator==(const reference &, const reference &);
b[5] = true; // assignment on reference
assert(b[5] == true); // and actually it does work.

هذا الكود يحتوي في الواقع على عيب ، حاول تشغيل:

std::for_each(&b[5], &b[6], some_func); // address of reference not an iterator

لن تعمل لأن assert( (&b[5] - &b[3]) == (5 - 3) ); ستفشل (ضمن llvm::BitVector)

هذا هو الإصدار llvm بسيط جدا. يحتوي std::vector<bool> أيضًا على متكررين يعملون فيه. وبالتالي فإن الدعوة for(auto i = b.begin(), e = b.end(); i != e; ++i) ستعمل. وكذلك std::vector<bool>::const_iterator.

ومع ذلك ، لا تزال هناك قيود في std::vector<bool> تجعله يتصرف بشكل مختلف في بعض الحالات.

4
Alex

هذا يأتي من http://www.cplusplus.com/reference/vector/vector-bool/

Vector of bool هذا هو إصدار متخصص من vector ، والذي يستخدم لعناصر type bool ويحسن المساحة.

يتصرف مثل الإصدار غير المتخصص للناقلات ، مع التغييرات التالية:

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

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

bitset هي فئة توفر وظيفة مماثلة لصفيفات البتات ذات الحجم الثابت.

3
kvv