Item 18 dari buku Scott Meyers Effective STL: 50 Specific Ways to Impro your Use of Standard Template Library mengatakan untuk menghindari vector <bool>
karena ini bukan wadah STL dan tidak benar-benar menahan bool
.
Kode berikut:
vector <bool> v;
bool *pb =&v[0];
tidak akan dikompilasi, melanggar persyaratan kontainer STL.
Kesalahan:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector<T>::operator []
tipe pengembalian seharusnya T&
, tetapi mengapa ini kasus khusus vector<bool>
?
Sebenarnya vector<bool>
terdiri dari apa?
Item lebih lanjut mengatakan:
deque<bool> v; // is a STL container and it really contains bools
Bisakah ini digunakan sebagai alternatif vector<bool>
?
Adakah yang bisa menjelaskan ini?
bool
, karena elemen tersebut tidak memiliki alamatnya sendiri.std::vector<bool> v;
akan dikompilasi.&v[0]
tidak akan (mengambil alamat sementara).vector<bool>
memiliki reputasi yang buruk tetapi tidak sepenuhnya dapat dibenarkan jadi: isocpp.org/blog/2012/11/on-vectorboolJawaban:
Untuk alasan pengoptimalan ruang, standar C ++ (sejauh C ++ 98) secara eksplisit memanggil
vector<bool>
sebagai wadah standar khusus di mana setiap bool hanya menggunakan satu bit ruang daripada satu byte seperti yang biasa dilakukan bool (mengimplementasikan semacam "bitset dinamis"). Sebagai imbalan atas pengoptimalan ini, ia tidak menawarkan semua kemampuan dan antarmuka penampung standar normal.Dalam kasus ini, karena Anda tidak dapat mengambil alamat bit dalam satu byte, hal-hal seperti
operator[]
tidak dapat mengembalikanbool&
tetapi sebaliknya mengembalikan objek proxy yang memungkinkan untuk memanipulasi bit tertentu yang dimaksud. Karena objek proxy ini bukan abool&
, Anda tidak dapat menetapkan alamatnyabool*
seperti yang Anda bisa dengan hasil dari panggilan operator seperti itu pada wadah "normal". Pada gilirannya ini berarti itubool *pb =&v[0];
bukan kode yang valid.Di sisi lain
deque
tidak memiliki spesialisasi seperti itu yang dipanggil sehingga setiap bool mengambil byte dan Anda dapat mengambil alamat dari pengembalian nilaioperator[]
.Terakhir perhatikan bahwa implementasi pustaka standar MS (bisa dibilang) suboptimal karena menggunakan ukuran potongan kecil untuk deques, yang berarti bahwa menggunakan deque sebagai pengganti tidak selalu merupakan jawaban yang tepat.
sumber
std::array
hanyalah pembungkus template di sekitar array mentahT[n]
dengan beberapa fungsi pembantu sepertisize()
, salin / pindahkan semantik, dan iterator ditambahkan untuk membuatnya kompatibel dengan STL - dan (untungnya) itu tidak melanggar prinsipnya sendiri untuk (perhatikan saya skeptisisme :) ini 'mengkhususkan' untuk 'bool
'.vector<bool>
berisi nilai boolean dalam bentuk terkompresi hanya menggunakan satu bit untuk nilai (dan bukan 8 bagaimana array bool [] lakukan). Tidak mungkin mengembalikan referensi ke sedikit di c ++, jadi ada jenis pembantu khusus, "referensi bit", yang memberi Anda antarmuka ke beberapa bit dalam memori dan memungkinkan Anda menggunakan operator dan cast standar.sumber
deque<bool>
tidak terspesialisasi jadi ini benar-benar hanya alat penahan deque.vector<bool>
memiliki implementasi template khusus. Saya kira, kontainer STL lain, sepertideque<bool>
, jangan, jadi mereka menyimpan bool-s seperti jenis lainnya.Masalahnya adalah bahwa
vector<bool>
mengembalikan objek referensi proxy dan bukan referensi yang benar, sehingga kode gaya C ++ 98bool * p = &v[0];
tidak dapat dikompilasi. Namun, C ++ 11 modern denganauto p = &v[0];
dapat dibuat untuk dikompilasi jikaoperator&
juga mengembalikan objek penunjuk proxy . Howard Hinnant telah menulis entri blog yang merinci peningkatan algoritmik saat menggunakan referensi dan penunjuk proxy tersebut.Scott Meyers memiliki Item panjang 30 di C ++ Lebih Efektif tentang kelas proxy. Anda bisa datang jauh untuk hampir meniru tipe bawaan: untuk tipe tertentu
T
, sepasang proxy (misalnyareference_proxy<T>
daniterator_proxy<T>
) dapat dibuat saling konsisten dalam artireference_proxy<T>::operator&()
daniterator_proxy<T>::operator*()
merupakan kebalikan satu sama lain.Namun, pada titik tertentu seseorang perlu memetakan objek proxy kembali untuk berperilaku seperti
T*
atauT&
. Untuk proxy iterator, seseorang dapat membebanioperator->()
dan mengaksesT
antarmuka template tanpa menjalankan kembali semua fungsionalitasnya. Namun, untuk proxy referensi, Anda perlu melakukan overloadoperator.()
, dan hal itu tidak diizinkan di C ++ saat ini (meskipun Sebastian Redl mempresentasikan proposal seperti itu di BoostCon 2013). Anda dapat membuat pekerjaan verbose seperti.get()
anggota di dalam proxy referensi, atau menerapkan semuaT
antarmuka di dalam referensi (inilah yang dilakukan untukvector<bool>::bit_reference
), tetapi ini akan kehilangan sintaks bawaan atau memperkenalkan konversi yang ditentukan pengguna yang tidak memiliki semantik bawaan untuk konversi jenis (Anda dapat memiliki paling banyak satu konversi yang ditentukan pengguna per argumen).TL; DR : tidak
vector<bool>
bukan wadah karena Standar memerlukan referensi nyata, tetapi dapat dibuat untuk berperilaku hampir seperti wadah, setidaknya lebih dekat dengan C ++ 11 (otomatis) daripada di C ++ 98.sumber
Banyak yang menganggap
vector<bool>
spesialisasi sebagai kesalahan.Dalam makalah "Deprecating Vestigial Library Parts in C ++ 17"
Ada proposal untuk Mempertimbangkan Kembali Vector Partial Specialization .
sumber
Lihatlah bagaimana ini diterapkan. STL sangat banyak dibangun di atas template dan oleh karena itu header berisi kode yang mereka lakukan.
misalnya lihat implementasi stdc ++ di sini .
juga menarik meskipun bukan vektor bit sesuai stl adalah llvm :: BitVector dari sini .
inti dari
llvm::BitVector
ini adalah kelas bersarang yang dipanggilreference
dan operator yang overloading cocok untuk membuatBitVector
perilaku serupavector
dengan beberapa batasan. Kode di bawah ini adalah antarmuka yang disederhanakan untuk menunjukkan bagaimana BitVector menyembunyikan kelas yang dipanggilreference
untuk membuat implementasi nyata hampir berperilaku seperti array bool nyata tanpa menggunakan 1 byte untuk setiap nilai.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; };
kode ini di sini memiliki properti yang bagus:
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.
Kode ini sebenarnya memiliki kekurangan, coba jalankan:
std::for_each(&b[5], &b[6], some_func); // address of reference not an iterator
tidak akan berfungsi karena
assert( (&b[5] - &b[3]) == (5 - 3) );
akan gagal (dalamllvm::BitVector
)ini adalah versi llvm yang sangat sederhana.
std::vector<bool>
juga bekerja iterator di dalamnya. dengan demikian panggilan itufor(auto i = b.begin(), e = b.end(); i != e; ++i)
akan berhasil. dan jugastd::vector<bool>::const_iterator
.Namun masih ada batasan
std::vector<bool>
yang membuatnya berperilaku berbeda dalam beberapa kasus.sumber
Ini berasal dari http://www.cplusplus.com/reference/vector/vector-bool/
sumber