Bagaimana cara memilih container Library Standar secara efisien di C ++ 11?
136
Ada gambar terkenal (lembar contekan) yang disebut "C ++ Container choice". Ini adalah diagram alir untuk memilih penampung terbaik untuk penggunaan yang diinginkan.
Belum pernah melihat ini sebelumnya. Terima kasih!
WeaselFox
6
@WeaselFox: Ini sudah menjadi bagian dari C ++ - Faq di SO.
Alok Save
4
C ++ 11 hanya memperkenalkan satu jenis container baru: container unordered_X. Memasukkannya hanya akan mengacaukan tabel, karena ada sejumlah pertimbangan saat memutuskan apakah tabel hash sesuai.
Nicol Bolas
13
James benar, ada lebih banyak kasus menggunakan vektor daripada yang ditunjukkan tabel. Keuntungan dari lokalitas data mengungguli dalam banyak kasus kurangnya efisiensi dalam beberapa operasi (lebih cepat lagi C ++ 11). Saya tidak menemukan grafik yang begitu berguna bahkan untuk c ++ 03
David Rodríguez - dribeas
34
Ini lucu, tetapi saya pikir membaca buku teks umum tentang struktur data akan membuat Anda berada dalam keadaan di mana Anda tidak hanya dapat menemukan kembali diagram alur ini dalam beberapa menit, tetapi juga mengetahui lebih banyak hal berguna yang disorot diagram alur ini.
Andrew Tomazos
Jawaban:
97
Setahu saya tidak, namun itu bisa dilakukan secara tekstual. Juga, bagannya sedikit melenceng, karena listbukan merupakan wadah yang baik secara umum, begitu pula halnya forward_list. Kedua daftar tersebut adalah wadah yang sangat khusus untuk aplikasi khusus.
Untuk membuat bagan seperti itu, Anda hanya perlu dua pedoman sederhana:
Pilih semantik terlebih dahulu
Ketika beberapa pilihan tersedia, pilih yang paling sederhana
Khawatir tentang kinerja biasanya tidak berguna pada awalnya. Pertimbangan O besar hanya benar-benar muncul ketika Anda mulai menangani beberapa ribu (atau lebih) item.
Ada dua kategori besar wadah:
Kontainer asosiatif : mereka memiliki findoperasi
Kontainer Urutan sederhana
dan kemudian Anda dapat membangun beberapa adapter di atas mereka: stack, queue, priority_queue. Saya akan meninggalkan adaptornya di sini, mereka cukup terspesialisasi agar dapat dikenali.
Pertanyaan 1: Asosiatif ?
Jika Anda perlu mencari dengan mudah dengan satu kunci, maka Anda memerlukan wadah asosiatif
Jika Anda perlu mengurutkan elemen, Anda memerlukan wadah asosiatif yang dipesan
Jika tidak, lompat ke pertanyaan 2.
Pertanyaan 1.1: Dipesan ?
Jika Anda tidak memerlukan pesanan khusus, gunakan unordered_wadah, jika tidak gunakan pesanan pesanan tradisionalnya.
Pertanyaan 1.2: Kunci Terpisah ?
Jika kunci terpisah dari nilainya, gunakan a map, jika tidak gunakan aset
Pertanyaan 1.3: Duplikat ?
Jika Anda ingin menyimpan duplikat, gunakan a multi, jika tidak, jangan.
Contoh:
Misalkan saya memiliki beberapa orang dengan ID unik yang terkait dengannya, dan saya ingin mengambil data seseorang dari ID-nya sesederhana mungkin.
Saya ingin sebuah findfungsi, jadi wadah asosiatif
1.1. Saya tidak peduli tentang pesanan, jadi sebuah unordered_wadah
1.2. Kunci saya (ID) terpisah dari nilai yang diasosiasikan dengannya, jadi amap
1.3. ID-nya unik, jadi tidak ada duplikat yang masuk.
Jawaban akhir adalah: std::unordered_map<ID, PersonData>.
Pertanyaan 2: Memori stabil ?
Jika elemen harus stabil dalam memori (yaitu, mereka tidak boleh berpindah-pindah saat wadah itu sendiri dimodifikasi), maka gunakan beberapa list
Jika tidak, lompat ke pertanyaan 3.
Pertanyaan 2.1: Yang mana ?
Setel untuk a list; a forward_listhanya berguna untuk footprint memori yang lebih rendah.
Pertanyaan 3: Berukuran dinamis ?
Jika penampung memiliki ukuran yang diketahui (pada waktu kompilasi), dan ukuran ini tidak akan diubah selama program berjalan, dan elemennya dapat dibangun secara default atau Anda dapat memberikan daftar inisialisasi lengkap (menggunakan { ... }sintaks), lalu gunakan array. Ini menggantikan C-array tradisional, tetapi dengan fungsi yang nyaman.
Jika tidak, lompat ke pertanyaan 4.
Pertanyaan 4: Berujung ganda ?
Jika Anda ingin menghapus item dari depan dan belakang, gunakan a deque, jika tidak gunakan a vector.
Anda akan mencatat bahwa, secara default, kecuali Anda membutuhkan wadah asosiatif, pilihan Anda adalah a vector. Ternyata itu juga rekomendasi Sutter dan Stroustrup .
+1, tetapi dengan beberapa catatan: 1) arraytidak memerlukan tipe konstruktif default; 2) memilih multis tidak terlalu banyak tentang duplikat yang diizinkan tetapi lebih tentang apakah menyimpannya penting (Anda dapat meletakkan duplikat di non- multicontainer, kebetulan hanya satu yang disimpan).
R. Martinho Fernandes
2
Contohnya agak salah. 1) kita dapat "menemukan" (bukan fungsi anggota, "<algorithm>" satu) pada wadah non asosiatif, 1.1) jika kita perlu menemukan "efisien", dan unordered_ akan menjadi O (1) dan bukan O ( log n).
BlakBat
4
@BlakBat: map.find(key)jauh lebih enak dari pada std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));meskipun, oleh karena itu penting, secara semantik, itu findadalah fungsi anggota dan bukan dari <algorithm>. Adapun O (1) vs O (log n), itu tidak mempengaruhi semantik; Saya akan menghapus "efisien" dari contoh dan menggantinya dengan "dengan mudah".
Matthieu M.
"Jika elemen harus stabil di memori ... maka gunakan beberapa daftar" ... hmmm, saya pikir dequepunya properti ini juga?
Martin Ba
@MartinBa: Ya dan tidak. Dalam sebuah dequeelemen stabil hanya jika Anda menekan / pop di kedua ujungnya; jika Anda mulai memasukkan / menghapus di tengah maka hingga N / 2 elemen dikocok untuk mengisi celah yang dibuat.
Matthieu M.
51
Saya suka jawaban Matthieu, tetapi saya akan mengulangi diagram alurnya seperti ini:
Kapan TIDAK menggunakan std :: vector
Secara default, jika Anda membutuhkan wadah barang, gunakan std::vector. Dengan demikian, setiap penampung lain hanya dibenarkan dengan menyediakan beberapa alternatif fungsionalitas std::vector.
Konstruktor
std::vectormengharuskan isinya dapat dipindahkan, karena harus dapat mengocok item di sekitar. Ini bukan beban yang berat untuk ditempatkan pada konten (perhatikan bahwa konstruktor default tidak diperlukan , berkat emplacedan sebagainya). Namun, sebagian besar wadah lain tidak memerlukan konstruktor tertentu (sekali lagi, terima kasih emplace). Jadi jika Anda memiliki objek di mana Anda sama sekali tidak dapat mengimplementasikan konstruktor pemindahan, maka Anda harus memilih yang lain.
A std::dequeakan menjadi pengganti umum, memiliki banyak properti std::vector, tetapi Anda hanya dapat memasukkan di kedua ujung deque. Sisipan di tengah perlu dipindahkan. A std::listtidak mensyaratkan isinya.
Membutuhkan Bools
std::vector<bool>tidak. Ya, ini standar. Tapi itu bukan vectordalam arti biasa, karena operasi yang std::vectorbiasanya memungkinkan dilarang. Dan itu pasti tidak mengandung bools .
Oleh karena itu, jika Anda memerlukan vectorperilaku nyata dari wadah bools, Anda tidak akan mendapatkannya std::vector<bool>. Jadi, Anda harus membayar dengan a std::deque<bool>.
Mencari
Jika Anda perlu menemukan elemen dalam sebuah wadah, dan tag pencarian tidak bisa hanya berupa indeks, maka Anda mungkin perlu meninggalkannya std::vectordemi setdan map. Perhatikan kata kunci " mungkin "; penyortiran std::vectorterkadang merupakan alternatif yang masuk akal. Atau Boost.Container's flat_set/map, yang mengimplementasikan file std::vector.
Sekarang ada empat variasi, masing-masing dengan kebutuhannya sendiri.
Gunakan mapjika tag pencarian tidak sama dengan item yang Anda cari sendiri. Jika tidak, gunakan a set.
Gunakan unorderedjika Anda memiliki banyak item dalam penampung dan kinerja penelusuran benar-benar perlu O(1), bukan O(logn).
Gunakan multijika Anda membutuhkan banyak item untuk memiliki tag pencarian yang sama.
Memerintah
Jika Anda membutuhkan penampung item untuk selalu diurutkan berdasarkan operasi perbandingan tertentu, Anda dapat menggunakan file set. Atau multi_setjika Anda membutuhkan beberapa item untuk memiliki nilai yang sama.
Atau Anda dapat menggunakan penyortiran std::vector, tetapi Anda harus tetap menyortirnya.
Stabilitas
Ketika iterator dan referensi tidak valid terkadang menjadi perhatian. Jika Anda memerlukan daftar item, sehingga Anda memiliki iterator / penunjuk ke item tersebut di berbagai tempat lain, maka std::vectorpendekatan pembatalan mungkin tidak tepat. Setiap operasi penyisipan dapat menyebabkan pembatalan, tergantung pada ukuran dan kapasitas saat ini.
std::listmenawarkan jaminan pasti: iterator dan referensi / petunjuk terkaitnya hanya tidak valid saat item itu sendiri dikeluarkan dari wadah. std::forward_listapakah ada jika ingatan menjadi perhatian serius.
Jika itu jaminan yang terlalu kuat, std::dequetawarkan jaminan yang lebih lemah tapi berguna. Hasil invalidasi dari penyisipan di tengah, tetapi penyisipan di kepala atau ekor hanya menyebabkan pembatalan iterator , bukan penunjuk / referensi ke item dalam penampung.
Kinerja Penyisipan
std::vector hanya menyediakan penyisipan murah di akhir (dan bahkan kemudian, menjadi mahal jika Anda meniup kapasitas).
std::listmahal dalam hal performa (setiap item yang baru dimasukkan memerlukan alokasi memori), tetapi konsisten . Ini juga menawarkan kemampuan yang kadang-kadang sangat diperlukan untuk mengocok barang-barang dengan hampir tanpa biaya kinerja, serta untuk menukar barang dengan std::listwadah lain dari jenis yang sama tanpa kehilangan kinerja. Jika Anda perlu untuk mengocok hal-hal di sekitar banyak , penggunaan std::list.
std::dequemenyediakan penyisipan / pemindahan waktu konstan di kepala dan ekor, tetapi penyisipan di tengah bisa cukup mahal. Jadi jika Anda perlu menambah / menghapus barang dari depan maupun belakang, std::dequemungkin yang Anda butuhkan.
Perlu dicatat bahwa, berkat semantik pemindahan, std::vectorkinerja penyisipan mungkin tidak seburuk dulu. Beberapa implementasi menerapkan bentuk penyalinan item berbasis semantik pemindahan (yang disebut "swaptimization"), tetapi sekarang pemindahan adalah bagian dari bahasa, itu diamanatkan oleh standar.
Tidak Ada Alokasi Dinamis
std::arrayadalah wadah yang bagus jika Anda menginginkan alokasi dinamis sesedikit mungkin. Ini hanya pembungkus di sekitar C-array; ini berarti ukurannya harus diketahui pada saat kompilasi . Jika Anda bisa hidup dengan itu, maka gunakan std::array.
Karena itu, menggunakan std::vectordan reservemengukur ukuran akan bekerja dengan baik untuk yang dibatasi std::vector. Dengan cara ini, ukuran sebenarnya dapat bervariasi, dan Anda hanya mendapatkan satu alokasi memori (kecuali jika kapasitasnya habis).
Yah, saya juga suka jawaban Anda :) WRT menjaga vektor diurutkan, selain dari std::sort, ada juga std::inplace_mergeyang menarik untuk dengan mudah menempatkan elemen baru (daripada panggilan std::lower_bound+ std::vector::insert). Senang belajar tentang flat_setdan flat_map!
Matthieu M.
2
Anda juga tidak dapat menggunakan vektor dengan tipe selaras 16-byte. Juga pengganti yang bagus untuk vector<bool>itu vector<char>.
Terbalik
@Inverse: "Anda juga tidak dapat menggunakan vektor dengan tipe selaras 16-byte." Kata siapa? Jika std::allocator<T>tidak mendukung perataan itu (dan saya tidak tahu mengapa tidak), maka Anda selalu dapat menggunakan pengalokasi khusus Anda sendiri.
Nicol Bolas
2
@Inverse: C ++ 11 std::vector::resizememiliki kelebihan beban yang tidak mengambil nilai (hanya mengambil ukuran baru; elemen baru akan dibuat secara default di tempat). Juga, mengapa kompiler tidak dapat menyelaraskan parameter nilai dengan benar, bahkan ketika mereka dinyatakan memiliki keselarasan itu?
@NO_NAME Wow, aku senang seseorang mau repot-repot mengutip sebuah sumber.
underscore_d
1
Ini putaran cepat, meskipun mungkin perlu diperbaiki
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
Anda mungkin memperhatikan bahwa ini sangat berbeda dari versi C ++ 03, terutama karena fakta bahwa saya benar-benar tidak menyukai node yang terhubung. Penampung node yang ditautkan biasanya dapat dikalahkan kinerjanya oleh penampung yang tidak tertaut, kecuali dalam beberapa situasi yang jarang terjadi. Jika Anda tidak tahu apa situasi tersebut, dan memiliki akses untuk meningkatkan, jangan gunakan wadah node tertaut. (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset). Daftar ini sebagian besar berfokus pada penampung sisi kecil dan menengah, karena (A) itu 99,99% dari apa yang kita tangani dalam kode, dan (B) Sejumlah besar elemen membutuhkan algoritme khusus, bukan penampung yang berbeda.
Jawaban:
Setahu saya tidak, namun itu bisa dilakukan secara tekstual. Juga, bagannya sedikit melenceng, karena
list
bukan merupakan wadah yang baik secara umum, begitu pula halnyaforward_list
. Kedua daftar tersebut adalah wadah yang sangat khusus untuk aplikasi khusus.Untuk membuat bagan seperti itu, Anda hanya perlu dua pedoman sederhana:
Khawatir tentang kinerja biasanya tidak berguna pada awalnya. Pertimbangan O besar hanya benar-benar muncul ketika Anda mulai menangani beberapa ribu (atau lebih) item.
Ada dua kategori besar wadah:
find
operasidan kemudian Anda dapat membangun beberapa adapter di atas mereka:
stack
,queue
,priority_queue
. Saya akan meninggalkan adaptornya di sini, mereka cukup terspesialisasi agar dapat dikenali.Pertanyaan 1: Asosiatif ?
Pertanyaan 1.1: Dipesan ?
unordered_
wadah, jika tidak gunakan pesanan pesanan tradisionalnya.Pertanyaan 1.2: Kunci Terpisah ?
map
, jika tidak gunakan aset
Pertanyaan 1.3: Duplikat ?
multi
, jika tidak, jangan.Contoh:
Misalkan saya memiliki beberapa orang dengan ID unik yang terkait dengannya, dan saya ingin mengambil data seseorang dari ID-nya sesederhana mungkin.
Saya ingin sebuah
find
fungsi, jadi wadah asosiatif1.1. Saya tidak peduli tentang pesanan, jadi sebuah
unordered_
wadah1.2. Kunci saya (ID) terpisah dari nilai yang diasosiasikan dengannya, jadi a
map
1.3. ID-nya unik, jadi tidak ada duplikat yang masuk.
Jawaban akhir adalah:
std::unordered_map<ID, PersonData>
.Pertanyaan 2: Memori stabil ?
list
Pertanyaan 2.1: Yang mana ?
list
; aforward_list
hanya berguna untuk footprint memori yang lebih rendah.Pertanyaan 3: Berukuran dinamis ?
{ ... }
sintaks), lalu gunakanarray
. Ini menggantikan C-array tradisional, tetapi dengan fungsi yang nyaman.Pertanyaan 4: Berujung ganda ?
deque
, jika tidak gunakan avector
.Anda akan mencatat bahwa, secara default, kecuali Anda membutuhkan wadah asosiatif, pilihan Anda adalah a
vector
. Ternyata itu juga rekomendasi Sutter dan Stroustrup .sumber
array
tidak memerlukan tipe konstruktif default; 2) memilihmulti
s tidak terlalu banyak tentang duplikat yang diizinkan tetapi lebih tentang apakah menyimpannya penting (Anda dapat meletakkan duplikat di non-multi
container, kebetulan hanya satu yang disimpan).map.find(key)
jauh lebih enak dari padastd::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));
meskipun, oleh karena itu penting, secara semantik, itufind
adalah fungsi anggota dan bukan dari<algorithm>
. Adapun O (1) vs O (log n), itu tidak mempengaruhi semantik; Saya akan menghapus "efisien" dari contoh dan menggantinya dengan "dengan mudah".deque
punya properti ini juga?deque
elemen stabil hanya jika Anda menekan / pop di kedua ujungnya; jika Anda mulai memasukkan / menghapus di tengah maka hingga N / 2 elemen dikocok untuk mengisi celah yang dibuat.Saya suka jawaban Matthieu, tetapi saya akan mengulangi diagram alurnya seperti ini:
Kapan TIDAK menggunakan std :: vector
Secara default, jika Anda membutuhkan wadah barang, gunakan
std::vector
. Dengan demikian, setiap penampung lain hanya dibenarkan dengan menyediakan beberapa alternatif fungsionalitasstd::vector
.Konstruktor
std::vector
mengharuskan isinya dapat dipindahkan, karena harus dapat mengocok item di sekitar. Ini bukan beban yang berat untuk ditempatkan pada konten (perhatikan bahwa konstruktor default tidak diperlukan , berkatemplace
dan sebagainya). Namun, sebagian besar wadah lain tidak memerlukan konstruktor tertentu (sekali lagi, terima kasihemplace
). Jadi jika Anda memiliki objek di mana Anda sama sekali tidak dapat mengimplementasikan konstruktor pemindahan, maka Anda harus memilih yang lain.A
std::deque
akan menjadi pengganti umum, memiliki banyak propertistd::vector
, tetapi Anda hanya dapat memasukkan di kedua ujung deque. Sisipan di tengah perlu dipindahkan. Astd::list
tidak mensyaratkan isinya.Membutuhkan Bools
std::vector<bool>
tidak. Ya, ini standar. Tapi itu bukanvector
dalam arti biasa, karena operasi yangstd::vector
biasanya memungkinkan dilarang. Dan itu pasti tidak mengandungbool
s .Oleh karena itu, jika Anda memerlukan
vector
perilaku nyata dari wadahbool
s, Anda tidak akan mendapatkannyastd::vector<bool>
. Jadi, Anda harus membayar dengan astd::deque<bool>
.Mencari
Jika Anda perlu menemukan elemen dalam sebuah wadah, dan tag pencarian tidak bisa hanya berupa indeks, maka Anda mungkin perlu meninggalkannya
std::vector
demiset
danmap
. Perhatikan kata kunci " mungkin "; penyortiranstd::vector
terkadang merupakan alternatif yang masuk akal. Atau Boost.Container'sflat_set/map
, yang mengimplementasikan filestd::vector
.Sekarang ada empat variasi, masing-masing dengan kebutuhannya sendiri.
map
jika tag pencarian tidak sama dengan item yang Anda cari sendiri. Jika tidak, gunakan aset
.unordered
jika Anda memiliki banyak item dalam penampung dan kinerja penelusuran benar-benar perluO(1)
, bukanO(logn)
.multi
jika Anda membutuhkan banyak item untuk memiliki tag pencarian yang sama.Memerintah
Jika Anda membutuhkan penampung item untuk selalu diurutkan berdasarkan operasi perbandingan tertentu, Anda dapat menggunakan file
set
. Ataumulti_set
jika Anda membutuhkan beberapa item untuk memiliki nilai yang sama.Atau Anda dapat menggunakan penyortiran
std::vector
, tetapi Anda harus tetap menyortirnya.Stabilitas
Ketika iterator dan referensi tidak valid terkadang menjadi perhatian. Jika Anda memerlukan daftar item, sehingga Anda memiliki iterator / penunjuk ke item tersebut di berbagai tempat lain, maka
std::vector
pendekatan pembatalan mungkin tidak tepat. Setiap operasi penyisipan dapat menyebabkan pembatalan, tergantung pada ukuran dan kapasitas saat ini.std::list
menawarkan jaminan pasti: iterator dan referensi / petunjuk terkaitnya hanya tidak valid saat item itu sendiri dikeluarkan dari wadah.std::forward_list
apakah ada jika ingatan menjadi perhatian serius.Jika itu jaminan yang terlalu kuat,
std::deque
tawarkan jaminan yang lebih lemah tapi berguna. Hasil invalidasi dari penyisipan di tengah, tetapi penyisipan di kepala atau ekor hanya menyebabkan pembatalan iterator , bukan penunjuk / referensi ke item dalam penampung.Kinerja Penyisipan
std::vector
hanya menyediakan penyisipan murah di akhir (dan bahkan kemudian, menjadi mahal jika Anda meniup kapasitas).std::list
mahal dalam hal performa (setiap item yang baru dimasukkan memerlukan alokasi memori), tetapi konsisten . Ini juga menawarkan kemampuan yang kadang-kadang sangat diperlukan untuk mengocok barang-barang dengan hampir tanpa biaya kinerja, serta untuk menukar barang denganstd::list
wadah lain dari jenis yang sama tanpa kehilangan kinerja. Jika Anda perlu untuk mengocok hal-hal di sekitar banyak , penggunaanstd::list
.std::deque
menyediakan penyisipan / pemindahan waktu konstan di kepala dan ekor, tetapi penyisipan di tengah bisa cukup mahal. Jadi jika Anda perlu menambah / menghapus barang dari depan maupun belakang,std::deque
mungkin yang Anda butuhkan.Perlu dicatat bahwa, berkat semantik pemindahan,
std::vector
kinerja penyisipan mungkin tidak seburuk dulu. Beberapa implementasi menerapkan bentuk penyalinan item berbasis semantik pemindahan (yang disebut "swaptimization"), tetapi sekarang pemindahan adalah bagian dari bahasa, itu diamanatkan oleh standar.Tidak Ada Alokasi Dinamis
std::array
adalah wadah yang bagus jika Anda menginginkan alokasi dinamis sesedikit mungkin. Ini hanya pembungkus di sekitar C-array; ini berarti ukurannya harus diketahui pada saat kompilasi . Jika Anda bisa hidup dengan itu, maka gunakanstd::array
.Karena itu, menggunakan
std::vector
danreserve
mengukur ukuran akan bekerja dengan baik untuk yang dibatasistd::vector
. Dengan cara ini, ukuran sebenarnya dapat bervariasi, dan Anda hanya mendapatkan satu alokasi memori (kecuali jika kapasitasnya habis).sumber
std::sort
, ada jugastd::inplace_merge
yang menarik untuk dengan mudah menempatkan elemen baru (daripada panggilanstd::lower_bound
+std::vector::insert
). Senang belajar tentangflat_set
danflat_map
!vector<bool>
ituvector<char>
.std::allocator<T>
tidak mendukung perataan itu (dan saya tidak tahu mengapa tidak), maka Anda selalu dapat menggunakan pengalokasi khusus Anda sendiri.std::vector::resize
memiliki kelebihan beban yang tidak mengambil nilai (hanya mengambil ukuran baru; elemen baru akan dibuat secara default di tempat). Juga, mengapa kompiler tidak dapat menyelaraskan parameter nilai dengan benar, bahkan ketika mereka dinyatakan memiliki keselarasan itu?bitset
untuk bool jika Anda mengetahui ukurannya terlebih dahulu en.cppreference.com/w/cpp/utility/bitsetBerikut adalah versi C ++ 11 dari diagram alur di atas. [awalnya diposting tanpa atribusi ke penulis aslinya, Mikael Persson ]
sumber
Ini putaran cepat, meskipun mungkin perlu diperbaiki
Should the container let you manage the order of the elements? Yes: Will the container contain always exactly the same number of elements? Yes: Does the container need a fast move operator? Yes: std::vector No: std::array No: Do you absolutely need stable iterators? (be certain!) Yes: boost::stable_vector (as a last case fallback, std::list) No: Do inserts happen only at the ends? Yes: std::deque No: std::vector No: Are keys associated with Values? Yes: Do the keys need to be sorted? Yes: Are there more than one value per key? Yes: boost::flat_map (as a last case fallback, std::map) No: boost::flat_multimap (as a last case fallback, std::map) No: Are there more than one value per key? Yes: std::unordered_multimap No: std::unordered_map No: Are elements read then removed in a certain order? Yes: Order is: Ordered by element: std::priority_queue First in First out: std::queue First in Last out: std::stack Other: Custom based on std::vector????? No: Should the elements be sorted by value? Yes: boost::flat_set No: std::vector
Anda mungkin memperhatikan bahwa ini sangat berbeda dari versi C ++ 03, terutama karena fakta bahwa saya benar-benar tidak menyukai node yang terhubung. Penampung node yang ditautkan biasanya dapat dikalahkan kinerjanya oleh penampung yang tidak tertaut, kecuali dalam beberapa situasi yang jarang terjadi. Jika Anda tidak tahu apa situasi tersebut, dan memiliki akses untuk meningkatkan, jangan gunakan wadah node tertaut. (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset). Daftar ini sebagian besar berfokus pada penampung sisi kecil dan menengah, karena (A) itu 99,99% dari apa yang kita tangani dalam kode, dan (B) Sejumlah besar elemen membutuhkan algoritme khusus, bukan penampung yang berbeda.
sumber