Ada gambar terkenal (lembar contekan) yang disebut "C ++ Container choice". Ini adalah diagram alir untuk memilih penampung terbaik untuk penggunaan yang diinginkan.
Adakah yang tahu jika sudah ada versi C ++ 11?
Ini yang sebelumnya:

Ada gambar terkenal (lembar contekan) yang disebut "C ++ Container choice". Ini adalah diagram alir untuk memilih penampung terbaik untuk penggunaan yang diinginkan.
Adakah yang tahu jika sudah ada versi C ++ 11?
Ini yang sebelumnya:

Jawaban:
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:
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:
findoperasidan 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 asetPertanyaan 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 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 ?
listPertanyaan 2.1: Yang mana ?
list; a forward_listhanya berguna untuk footprint memori yang lebih rendah.Pertanyaan 3: Berukuran dinamis ?
{ ... }sintaks), lalu gunakan array. Ini menggantikan C-array tradisional, tetapi dengan fungsi yang nyaman.Pertanyaan 4: Berujung ganda ?
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 .
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).
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".
dequepunya properti ini juga?
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.
Saya suka jawaban Matthieu, tetapi saya akan mengulangi diagram alurnya seperti ini:
Secara default, jika Anda membutuhkan wadah barang, gunakan std::vector. Dengan demikian, setiap penampung lain hanya dibenarkan dengan menyediakan beberapa alternatif fungsionalitas std::vector.
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.
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>.
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.
mapjika tag pencarian tidak sama dengan item yang Anda cari sendiri. Jika tidak, gunakan a set.unorderedjika Anda memiliki banyak item dalam penampung dan kinerja penelusuran benar-benar perlu O(1), bukan O(logn).multijika Anda membutuhkan banyak item untuk memiliki tag pencarian yang sama.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.
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.
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.
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).
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!
vector<bool>itu vector<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::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?
bitsetuntuk bool jika Anda mengetahui ukurannya terlebih dahulu en.cppreference.com/w/cpp/utility/bitset
Berikut adalah versi C ++ 11 dari diagram alur di atas. [awalnya diposting tanpa atribusi ke penulis aslinya, Mikael Persson ]

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.