ทางเลือกสำหรับเวกเตอร์ <bool>


92

ตามที่ (หวังว่า) เราทุกคนรู้ว่าvector<bool>พังโดยสิ้นเชิงและไม่สามารถถือว่าเป็นอาร์เรย์ C ได้ วิธีที่ดีที่สุดในการรับฟังก์ชันนี้คืออะไร? จนถึงตอนนี้ความคิดที่ฉันคิดคือ:

  • ใช้vector<char>แทนหรือ
  • ใช้คลาส Wrapper และมี vector<bool_wrapper>

พวกคุณจัดการกับปัญหานี้อย่างไร? ฉันต้องการc_array()ฟังก์ชั่น

เป็นคำถามข้างเคียงถ้าฉันไม่ต้องการc_array()วิธีการใดวิธีที่ดีที่สุดในการแก้ไขปัญหานี้หากฉันต้องการเข้าถึงโดยสุ่ม ฉันควรใช้ deque หรืออย่างอื่น?

แก้ไข:

  • ฉันต้องการการปรับขนาดแบบไดนามิก
  • สำหรับผู้ที่ไม่ทราบvector<bool>มีความเชี่ยวชาญเพื่อให้boolใช้เวลา 1 บิต ดังนั้นคุณจึงไม่สามารถแปลงเป็นอาร์เรย์สไตล์ C ได้
  • ฉันเดาว่า "เสื้อคลุม" เป็นการเรียกชื่อผิด ฉันกำลังคิดบางอย่างเช่นนี้:

แน่นอนฉันต้องอ่านmy_boolเนื่องจากปัญหาการจัดตำแหน่งที่เป็นไปได้ :(

struct my_bool
{
    bool the_bool;
};
vector<my_bool> haha_i_tricked_you;

2
มีเหตุผลบางอย่างที่จะไม่ใช้ ... อาร์เรย์สไตล์ C หรือไม่?
kquinn

rlbond คุณต้องการขนาดไดนามิกหรือไม่?
Johannes Schaub - litb

16
ตกลงฉันจะกัด - ทำไมคุณถึงคิดว่าเวกเตอร์เป็น "" หักทั้งหมด "
Andrew Grant


4
ที่น่าสนใจvector<bool>เพิ่งทำให้เกิดข้อผิดพลาดในการแย่งชิงข้อมูลในโค้ดของฉันเนื่องจากฉันคาดว่าเธรดต่างๆจะสามารถแก้ไของค์ประกอบต่างๆในเวกเตอร์ได้ในเวลาเดียวกันอย่างปลอดภัย แก้ไขโดยใช้deque<bool>.
Andres Riofrio

คำตอบ:


42

ใช้std::dequeถ้าคุณไม่ต้องการอาร์เรย์ใช่

มิฉะนั้นจะใช้ทางเลือกvectorที่ไม่เชี่ยวชาญในการboolเช่นหนึ่งในBoost ตู้คอนเทนเนอร์


21

นั่นเป็นปัญหาที่น่าสนใจ

หากคุณต้องการสิ่งที่จะเป็น std :: vector ถ้ามันไม่เชี่ยวชาญบางทีบางอย่างก็ใช้ได้ดีกับกรณีของคุณ:

#include <vector>
#include <iostream> 
#include <algorithm>

class Bool
{
public:

    Bool(): m_value(){}
    Bool( bool value ) : m_value(value){}

    operator bool() const { return m_value; }

    // the following operators are to allow bool* b = &v[0]; (v is a vector here).
    bool* operator& () { return &m_value; }
    const bool* operator& () const { return &m_value; }

private:

    bool m_value;

};




int main()
{
    std::vector<Bool> working_solution(10, false);


    working_solution[5] = true;
    working_solution[7] = true;


    for( int i = 0; i < working_solution.size(); ++i )
    {
        std::cout<< "Id " << i << " = " << working_solution[i] << "(" <<(working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::sort( working_solution.begin(), working_solution.end());
    std::cout<< "--- SORTED! ---" << std::endl;

    for( int i = 0; i < working_solution.size(); ++i )
    {
            bool* b = &working_solution[i]; // this works!

        std::cout<< "Id " << i << " = " << working_solution[i] << "(" << (working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::cin.get();
    return 0;
}

ฉันลองกับ VC9 และดูเหมือนว่าจะทำงานได้ดี แนวคิดของคลาส Bool คือการจำลองประเภทบูลโดยให้พฤติกรรมและขนาดเดียวกัน (แต่ไม่ใช่ประเภทเดียวกัน) งานเกือบทั้งหมดทำโดยตัวดำเนินการบูลและตัวสร้างสำเนาเริ่มต้นที่นี่ ฉันเพิ่มการจัดเรียงเพื่อให้แน่ใจว่ามันตอบสนองตามที่สันนิษฐานไว้เมื่อใช้อัลกอริทึม

ไม่แน่ใจว่าจะเหมาะกับทุกกรณี ถ้ามันเหมาะกับความต้องการของคุณมันจะไม่ค่อยเวิร์คกว่าการเขียนคลาสแบบเวกเตอร์ใหม่ ...


"เราสามารถเพิ่มตัวดำเนินการ bool * & () {return & m_value;}" - err ISO : " sizeof(bool)ไม่จำเป็นต้องเป็น1"
Evgeny Panasyuk

2
ฉันต้องการเพียงแค่เปลี่ยนoperator bool() constเป็นoperator bool&()ไฟล์. สิ่งนี้ทำให้สะท้อนพฤติกรรมของบูลแบบธรรมดาได้ดีขึ้นเนื่องจากรองรับการมอบหมายงานเป็นต้นในกรณีเช่นv[0] = true;ฉันไม่เห็นปัญหาเกี่ยวกับการเปลี่ยนแปลงนี้ฉันจะทำการแก้ไขได้หรือไม่
Agentlien

19

ขึ้นอยู่กับความต้องการของคุณ. std::vector<unsigned char>ฉันจะไปอย่างใดอย่างหนึ่ง การเขียน Wrapper อาจทำได้ดีถ้าคุณใช้ฟังก์ชันการทำงานเพียงบางส่วนเท่านั้นมิฉะนั้นจะกลายเป็นฝันร้าย


unsigned charเป็นไบต์เดียวเสมอในขณะที่การใช้งานuint8_tอาจไม่รองรับ uint_fast8_tสามารถทำงานได้ แต่ถ้าเจตนาคือการทำให้มันชัดเจนว่ามันเป็นไบต์เดียวและไม่ได้ตัวละคร แต่คุณอาจรวมทั้งใช้std::byteแล้ว
กาเบรียล Ravier

13

พวกคุณจัดการกับปัญหานี้อย่างไร? ฉันต้องการฟังก์ชัน c_array ()

boost::container::vector<bool>:

ความเชี่ยวชาญของvector < bool > ค่อนข้างมีปัญหาและมีการพยายามเลิกใช้หรือลบออกจากมาตรฐานไม่สำเร็จหลายครั้ง Boost.Containerไม่ได้ใช้งานเนื่องจากมีโซลูชันBoost.DynamicBitset ที่เหนือกว่า

...

ดังนั้นboost :: container :: vector :: iteratorจะส่งคืนการอ้างอิงบูลจริงและทำงานเป็นคอนเทนเนอร์ที่สอดคล้องกันอย่างสมบูรณ์ หากคุณจำเป็นต้องมีหน่วยความจำรุ่นที่ดีที่สุดของการเพิ่ม :: ภาชนะ :: เวกเตอร์ < บูล > ฟังก์ชันกรุณาใช้Boost.DynamicBitset


6

พิจารณาใช้เวกเตอร์ <int> เมื่อคุณได้รับการรวบรวมและการตรวจสอบประเภทที่ผ่านมาบูลและ int เป็นเพียงคำพูดของเครื่อง (แก้ไข: เห็นได้ชัดว่านี่ไม่เป็นความจริงเสมอไป แต่จะเป็นจริงในสถาปัตยกรรมพีซีจำนวนมาก) ในกรณีที่คุณต้องการแปลงโดยไม่มีคำเตือนให้ใช้ "bool foo = !! bar" ซึ่งจะแปลงศูนย์เป็นเท็จและไม่เป็นศูนย์เป็นจริง

เวกเตอร์ <char> หรือคล้ายกันจะใช้พื้นที่น้อยกว่าแม้ว่าจะมีโอกาสที่จะตีความเร็ว (น้อยมาก) ได้ในบางสถานการณ์เนื่องจากอักขระน้อยกว่าขนาดคำของเครื่อง นี่คือฉันเชื่อว่าเหตุผลหลักที่บูลถูกนำมาใช้โดยใช้ ints แทนตัวอักษร

หากคุณต้องการความหมายที่สะอาดจริงๆฉันก็ชอบคำแนะนำในการสร้างคลาสบูลีนของคุณเอง - ดูเหมือนบูลทำหน้าที่เหมือนบูล แต่หลอกเฉพาะความเชี่ยวชาญของเทมเพลต

นอกจากนี้ยินดีต้อนรับสู่สโมสรของผู้ที่ต้องการความเชี่ยวชาญเวกเตอร์ <bool> ที่หลุดจากมาตรฐาน C ++ (โดยมี bit_vector เพื่อแทนที่) เป็นที่ที่เด็ก ๆ ทุกคนออกไปเที่ยว :)


4

ปัญหานี้ได้รับการกล่าวถึงแล้วบน comp.lang.c ++. แนวทางแก้ไขที่เสนอ:

  • ผู้จัดสรรของคุณเอง (ตามstd::allocator) และความเชี่ยวชาญเวกเตอร์ของตัวเอง
  • ใช้std::deque(ตามที่แนะนำไว้ในหนังสือเล่มหนึ่งของ S. Mayers) - แต่นี่ไม่ใช่สำหรับความต้องการของคุณ
  • ทำboolกระดาษห่อ POD
  • การใช้งานบางสิ่งบางอย่าง ( char/ int/ ฯลฯ ) ที่มีขนาดเดียวกับboolแทนbool;

ก่อนหน้านี้ฉันเห็นข้อเสนอสำหรับคณะกรรมการมาตรฐาน - แนะนำมาโคร (บางอย่างเช่นSTD_VECTOR_BOOL_SPECIAL) เพื่อไม่อนุญาตความเชี่ยวชาญนี้ - แต่ AFAIK ข้อเสนอนี้ไม่ได้ถูกนำไปใช้ในการใช้งาน stl และไม่ได้รับการอนุมัติ

ดูเหมือนว่าปัญหาของคุณจะไม่มีทางทำได้ดี ... อาจจะเป็นใน C ++ 0x


3

คำตอบที่ง่ายที่สุดคือการใช้งานvector<struct sb>ที่เป็นsb จากนั้นคุณสามารถพูดได้struct {boolean b}; push_back({true})ดูเหมือนว่าดี


2

วิธีแก้ปัญหาที่ฉันต้องการคือvectorขอบเขตขอบเขตที่มีประเภทพื้นฐานของbool. สิ่งนี้ค่อนข้างใกล้เคียงกับที่vector<bool>เรามีหากคณะกรรมการไม่มีความเชี่ยวชาญ

enum class switch_status : bool { ON, OFF };

static_assert( sizeof( switch_status ) == 1 );

::std::vector<switch_status> switches( 20, switch_status::ON );

static_assert( ::std::is_same_v< decltype( switches.front() ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches.back()  ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches[ 0 ]    ), switch_status &> );

คุณจะมีความคิดเห็นของคุณเองเกี่ยวกับภูมิปัญญาในการรวบรวมนักแสดงไป / กลับbool:

enum class switch_status : bool { OFF = false, ON = true };

static_assert( static_cast< bool          >( switch_status::ON  ) == true               );
static_assert( static_cast< bool          >( switch_status::OFF ) == false              );
static_assert( static_cast< switch_status >( true               ) == switch_status::ON  );
static_assert( static_cast< switch_status >( false              ) == switch_status::OFF );
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.