Alternatif untuk vektor <bool>

92

Seperti (semoga) kita semua tahu, vector<bool>benar-benar rusak dan tidak dapat diperlakukan sebagai array C. Apa cara terbaik untuk mendapatkan fungsi ini? Sejauh ini, ide yang saya pikirkan adalah:

  • Gunakan sebagai vector<char>gantinya, atau
  • Gunakan kelas pembungkus dan miliki vector<bool_wrapper>

Bagaimana kalian menangani masalah ini? Saya membutuhkan c_array()fungsionalitas tersebut.

Sebagai pertanyaan sampingan, jika saya tidak memerlukan c_array()metode ini, apa cara terbaik untuk mengatasi masalah ini jika saya memerlukan akses acak? Haruskah saya menggunakan deque atau yang lainnya?

Edit:

  • Saya membutuhkan ukuran dinamis.
  • Bagi yang belum tahu, vector<bool>dikhususkan sehingga masing-masing boolbutuh 1 bit. Dengan demikian, Anda tidak dapat mengubahnya menjadi array gaya C.
  • Saya kira "wrapper" adalah istilah yang salah. Saya sedang memikirkan sesuatu seperti ini:

Tentu saja, saya harus membaca my_boolkarena kemungkinan masalah penyelarasan :(

struct my_bool
{
    bool the_bool;
};
vector<my_bool> haha_i_tricked_you;
rlbond.dll
sumber
2
Apakah ada alasan untuk tidak menggunakan ... array C-style?
kquinn
rlbond, apakah Anda membutuhkan ukuran dinamis?
Johannes Schaub - litb
16
Oke, saya akan menggigit - mengapa menurut Anda vektor "" benar-benar rusak "?
Andrew Grant
8
@Andrew Grant - lihat open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2160.html
Daniel Earwicker
4
Menariknya, vector<bool>hanya menyebabkan bug data race dalam kode saya, karena saya mengharapkan utas yang berbeda dapat memodifikasi elemen yang berbeda dalam vektor pada saat yang sama dengan aman. Diselesaikan menggunakan deque<bool>.
Andres Riofrio

Jawaban:

42

Gunakan std::dequejika Anda tidak membutuhkan array, ya.

Jika tidak, gunakan alternatif vectoryang tidak mengkhususkan bool, seperti yang ada di Boost Container .

Daniel Earwicker
sumber
21

Itu masalah yang menarik.

Jika Anda memerlukan apa yang akan menjadi std :: vector jika tidak terspesialisasi, maka mungkin sesuatu seperti itu akan bekerja dengan baik dengan kasus Anda:

#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;
}

Saya mencoba ini dengan VC9 dan tampaknya berfungsi dengan baik. Ide dari kelas Bool adalah untuk mensimulasikan tipe bool dengan menyediakan perilaku dan ukuran yang sama (tapi bukan tipe yang sama). Hampir semua pekerjaan dilakukan oleh operator bool dan konstruktor salinan default di sini. Saya menambahkan semacam untuk memastikannya bereaksi seperti yang diasumsikan saat menggunakan algoritma.

Tidak yakin itu akan cocok untuk semua kasus. Jika itu tepat untuk kebutuhan Anda, itu akan lebih mudah daripada menulis ulang kelas seperti vektor ...

Klaim
sumber
"kita bisa menambahkan bool * operator & () {return & m_value;}" - err. ISO : " sizeof(bool)tidak harus ada 1"
Evgeny Panasyuk
2
Saya lebih suka mengubah operator bool() constke file operator bool&(). Ini membuatnya mencerminkan perilaku bool sederhana dengan lebih baik karena mendukung penugasan, dll. Dalam kasus seperti v[0] = true;saya benar-benar tidak dapat melihat masalah dengan perubahan ini, jadi bolehkah saya mengeditnya?
Agentlien
19

Tergantung kebutuhan Anda. Saya akan memilih keduanya std::vector<unsigned char>. Menulis pembungkus bisa baik-baik saja jika Anda hanya menggunakan sebagian dari fungsionalitas, jika tidak maka akan menjadi mimpi buruk.

David Rodríguez - dribeas
sumber
unsigned charselalu berupa satu byte sementara uint8_tmungkin tidak didukung oleh implementasi. uint_fast8_tbisa bekerja meskipun jika tujuannya adalah untuk membuatnya jelas itu satu byte dan bukan karakter, tapi Anda mungkin juga menggunakan std::bytekemudian
Gabriel Ravier
13

Bagaimana kalian menangani masalah ini? Saya membutuhkan fungsionalitas c_array ().

boost::container::vector<bool>:

vektor < bool > spesialisasi telah cukup bermasalah, dan ada beberapa percobaan yang gagal untuk menghentikan atau menghapusnya dari standar. Boost.Containertidak mengimplementasikannya karena ada solusi Boost.DynamicBitset yang superior .

...

Jadi boost :: container :: vector :: iterator mengembalikan referensi bool nyata dan berfungsi sebagai container yang sepenuhnya sesuai. Jika Anda membutuhkan versi yang dioptimalkan untuk fungsi boost :: container :: vector < bool >, gunakan Boost.DynamicBitset .

Evgeny Panasyuk
sumber
6

Pertimbangkan untuk menggunakan vektor <int>. Setelah Anda melewati kompilasi dan pengecekan tipe, bool dan int keduanya hanyalah kata-kata mesin (edit: tampaknya ini tidak selalu benar; tetapi akan benar pada banyak arsitektur PC). Dalam kasus di mana Anda ingin mengonversi tanpa peringatan, gunakan "bool foo = !! bar", yang mengonversi nol menjadi salah dan bukan nol menjadi benar.

Sebuah vektor <char> atau yang serupa akan menggunakan lebih sedikit ruang, meskipun itu juga berpotensi untuk menerima kecepatan (sangat kecil) dalam beberapa keadaan, karena karakter lebih kecil dari ukuran kata mesin. Ini, saya yakin, alasan utama bools diimplementasikan menggunakan int, bukan chars.

Jika Anda benar-benar ingin semantik yang bersih, saya juga menyukai saran untuk membuat kelas boolean Anda sendiri - terlihat seperti bool, berfungsi seperti bool, tetapi menipu spesialisasi template.

Juga, selamat datang di klub orang-orang yang menginginkan spesialisasi vektor <bool> diturunkan dari standar C ++ (dengan bit_vector untuk menggantikannya). Itu tempat berkumpulnya anak-anak keren :).

AHelps
sumber
4

Masalah ini telah dibahas di comp.lang.c ++. Dimoderasi. Solusi yang diusulkan:

  • pengalokasi Anda sendiri (berdasarkan std::allocator) dan spesialisasi vektor sendiri;
  • gunakan std::deque(seperti yang disarankan di awal dalam salah satu buku S. Mayers) - tetapi ini bukan untuk kebutuhan Anda;
  • membuat boolpembungkus POD ;
  • gunakan sesuatu ( char/ int/ etc) dengan ukuran yang sama sebagai boolgantinya bool;

Juga awal saya melihat proposal untuk komite standar - memperkenalkan makro (seperti STD_VECTOR_BOOL_SPECIAL) untuk melarang spesialisasi ini - tetapi AFAIK proposal ini tidak diimplementasikan dalam implementasi stl dan tidak disetujui.

Tampaknya masalah Anda tidak memiliki cara untuk melakukannya dengan baik ... Mungkin di C ++ 0x.

bayda
sumber
3

Jawaban paling sederhana adalah penggunaan vector<struct sb>mana sbadalah struct {boolean b};. Kemudian Anda bisa mengatakan push_back({true}). Sepertinya bagus.

Todd
sumber
2

Solusi pilihan saya adalah vectorenum terbatas yang memiliki jenis yang mendasari bool. Ini hampir sama dengan yang vector<bool>akan kami alami jika komite tidak mengkhususkannya.

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 &> );

Anda akan memiliki pendapat sendiri tentang kebijaksanaan merangkul pemain ke / dari 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 );
Tony E Lewis
sumber