Saya banyak menggunakan std::set<int>
dan seringkali saya hanya perlu memeriksa apakah set seperti itu berisi angka atau tidak.
Menurut saya wajar untuk menulis:
if (myset.contains(number))
...
Tetapi karena kekurangan contains
anggota, saya perlu menulis yang rumit:
if (myset.find(number) != myset.end())
..
atau yang tidak begitu jelas:
if (myset.count(element) > 0)
..
Apakah ada alasan untuk keputusan desain ini?
count()
pendekatan ini adalah bahwa ia melakukan lebih banyak pekerjaan daripada yangcountains()
harus dilakukan.contains()
yang mengembalikan sebuahbool
akan kehilangan informasi berharga tentang di mana unsur ini dalam koleksi .find()
mempertahankan dan mengembalikan informasi tersebut dalam bentuk iterator, oleh karena itu merupakan pilihan yang lebih baik untuk pustaka generik seperti STL. (Itu tidak berarti bahwa abool contains()
tidak terlalu bagus untuk dimiliki atau bahkan diperlukan.)contains(set, element)
fungsi gratis menggunakan antarmuka publik set. Oleh karena itu, antarmuka himpunan secara fungsional lengkap; menambahkan metode kenyamanan hanya meningkatkan antarmuka tanpa mengaktifkan fungsi tambahan apa pun, yang bukan merupakan cara C ++.Jawaban:
Saya rasa itu mungkin karena mereka berusaha membuat
std::set
danstd::multiset
semirip mungkin. (Dan jelascount
memiliki arti yang sangat masuk akal untukstd::multiset
.)Secara pribadi saya pikir ini adalah kesalahan.
Tidak terlalu buruk jika Anda berpura-pura bahwa
count
itu hanya salah ejacontains
dan menulis tes sebagai:Itu masih memalukan.
sumber
.end()
).contains()
karena itu akan mubazir karena untuk setiapstd::set<T> s
danT t
, hasil daris.contains(t)
sama persis dengan hasilstatic_cast<bool>(s.count(t))
. Karena menggunakan nilai dalam ekspresi kondisional secara implisit akan mentransmisikannyabool
, mereka mungkin merasa bahwa itucount()
memenuhi tujuan dengan cukup baik.if (myset.ICanHaz(element)) ...
: DUntuk dapat menulis
if (s.contains())
,contains()
harus mengembalikanbool
(atau tipe yang dapat dikonversibool
, yang merupakan cerita lain), sepertibinary_search
halnya.The alasan mendasar di balik keputusan desain tidak untuk melakukannya dengan cara ini adalah bahwa
contains()
yang mengembalikanbool
akan kehilangan informasi berharga tentang di mana unsur ini dalam koleksi .find()
mempertahankan dan mengembalikan informasi tersebut dalam bentuk iterator, oleh karena itu merupakan pilihan yang lebih baik untuk pustaka generik seperti STL. Ini selalu menjadi prinsip panduan Alex Stepanov, seperti yang sering dia jelaskan (misalnya, di sini ).Mengenai
count()
pendekatan secara umum, meskipun sering kali merupakan solusi yang baik, masalah dengan itu adalah bahwa ia melakukan lebih banyak pekerjaan daripada yangcontains()
harus dilakukan .Itu tidak berarti bahwa a
bool contains()
bukanlah sesuatu yang sangat bagus untuk dimiliki atau bahkan diperlukan. Beberapa waktu yang lalu kami berdiskusi panjang tentang masalah yang sama ini di grup ISO C ++ Standard - Future Proposals.sumber
contains()
, jelas, akan berinteraksi kuat dengan container dan algoritme yang ada, yang akan sangat dipengaruhi oleh konsep dan rentang - pada waktu yang diperkirakan akan masuk ke C ++ 17 - dan Saya yakin (sebagai hasil dari diskusi serta beberapa pertukaran email pribadi) bahwa lebih baik menunggu mereka terlebih dahulu. Tentu saja, pada tahun 2015 tidak jelas bahwa baik konsep maupun rentang tidak akan berhasil mencapai C ++ 17 (pada kenyataannya, ada harapan besar bahwa mereka akan berhasil). Saya tidak yakin itu layak untuk dikejar sekarang.std::set
(yang ditanyakan pertanyaannya), saya tidak melihat bagaimana caracount
melakukan lebih banyak pekerjaan daripada yangcontains
harus dilakukan. Implementasi glibccount
adalah (secara kasar)return find(value) == end() ? 0 : 1;
. Terlepas dari detail tentang operator terner vs hanya kembali!= end()
(yang saya harapkan akan dihapus oleh pengoptimal), saya tidak dapat melihat bagaimana ada pekerjaan lagi.myset.contains()
(jika ada), itu akan menjadi indikasi yang cukup kuat bahwa informasi itu tidak berharga ( kepada pengguna dalam konteks itu).count()
melakukan lebih banyak pekerjaan daripada yangcontains()
harus dilakukanstd::set
? Ini unik jadicount()
bisa sajareturn contains(x) ? 1 : 0;
yang persis sama.Itu kurang karena tidak ada yang menambahkannya. Tidak ada yang menambahkannya karena kontainer dari STL yang
std
dimasukkan perpustakaan dirancang untuk menjadi antarmuka yang minimal. (Perhatikan bahwastd::string
tidak berasal dari STL dengan cara yang sama).Jika Anda tidak keberatan dengan sintaks yang aneh, Anda dapat memalsukannya:
menggunakan:
Pada dasarnya, Anda dapat menulis metode ekstensi untuk sebagian besar
std
jenis C ++ menggunakan teknik ini.Jauh lebih masuk akal untuk hanya melakukan ini:
tapi saya terhibur dengan metode metode ekstensi.
Hal yang sangat menyedihkan adalah bahwa menulis efisien
contains
bisa lebih cepat padamultimap
ataumultiset
, karena mereka hanya perlu menemukan satu elemen, sementaracount
harus menemukan masing-masing dan menghitungnya .Sebuah multiset yang berisi 1 miliar salinan 7 (Anda tahu, seandainya kehabisan) bisa sangat lambat
.count(7)
, tetapi bisa sangat cepatcontains(7)
.Dengan metode ekstensi di atas, kita dapat mempercepat kasus ini dengan menggunakan
lower_bound
, membandingkanend
, dan kemudian membandingkan dengan elemen. Namun, melakukan itu untuk meong yang tidak berurutan serta meong yang dipesan akan membutuhkan SFINAE yang mewah atau kelebihan muatan khusus kontainer.sumber
std::set
tidak dapat berisi duplikat dan karena itustd::set::count
akan selalu kembali0
atau1
.std::multiset::count
canbackticks
sekitar kata "set" adalah karena saya tidak mengacustd::set
secara spesifik. Untuk membuat Anda merasa lebih baik, saya akan menambahkan multiAnda mencari kasus tertentu dan tidak melihat gambaran yang lebih besar. Sebagaimana dinyatakan dalam dokumentasi,
std::set
memenuhi persyaratan konsep AssociativeContainer . Untuk konsep itu tidak masuk akal untuk memilikicontains
metode, karena tidak banyak berguna untukstd::multiset
danstd::multimap
, tetapicount
berfungsi dengan baik untuk semuanya. Meskipun metodecontains
dapat ditambahkan sebagai alias untukcount
untukstd::set
,std::map
dan versi hash mereka (sepertilength
untuksize()
distd::string
), tapi terlihat seperti pencipta perpustakaan tidak melihat kebutuhan nyata untuk itu.sumber
string
adalah monster: ia ada sebelum STL, di mana ia memilikilength
dan semua metode yang berbasis indeks, dan kemudian "di-container" agar sesuai dengan model STL ... tanpa menghapus metode yang ada karena alasan kompatibilitas ke belakang . Lihat GotW # 84: Monoliths Unstrung =>string
benar-benar melanggar prinsip desain "jumlah minimum fungsi anggota".contains
sama dalam upaya pada satu set / map, tetapi bisa dibuat lebih cepat daricount
pada multiset / multimap.contains
metode.size()
danempty()
merupakan duplikat, namun banyak wadah memiliki keduanya.Meskipun saya tidak tahu mengapa
std::set
tidak adacontains
tetapicount
yang hanya pernah kembali0
atau1
, Anda dapat menuliscontains
fungsi pembantu template seperti ini:Dan gunakan seperti ini:
sumber
contains
metode tersebut ada, hanya dinamai dengan cara yang bodoh.std::string
batukstd.::string
BUKAN bagian dari STL! Ini adalah bagian dari perpustakaan standar dan memiliki template retroaktif ...count
bisa lebih lambat karena secara efektif perlu melakukan duafind
detik untuk mendapatkan awal dan akhir rentang jika kode dibagikanmultiset
.contains
. Saya tidak melihat ada yang salah dengan itu. @MarkRansom, SFINAE kecil adalah untuk mencegah templat ini mengikat hal-hal yang tidak semestinya.Alasan sebenarnya
set
adalah misteri bagi saya, tetapi satu kemungkinan penjelasan untuk desain yang sama inimap
adalah untuk mencegah orang menulis kode yang tidak efisien secara tidak sengaja:Yang akan menghasilkan dua
map
pencarian.Sebaliknya, Anda dipaksa untuk mendapatkan iterator. Ini memberi Anda petunjuk mental bahwa Anda harus menggunakan kembali iterator:
yang hanya menggunakan satu
map
pencarian.Ketika kita menyadarinya
set
danmap
dibuat dari daging yang sama, kita dapat menerapkan prinsip ini juga padaset
. Artinya, jika kita ingin bertindak atas item diset
hanya jika ada diset
, desain ini dapat mencegah kita menulis kode seperti ini:Tentu semua ini hanyalah spekulasi belaka.
sumber
if (myMap.count("Meaning of universe"))
baik, jadi ...?contains
seperti halnya dengancount
.Sejak c ++ 20,
bool contains( const Key& key ) const
tersedia.
sumber
Bagaimana dengan binary_search?
sumber
std::unordered_set
, tetapi untukstd::set
itu akan berhasil.berisi () harus mengembalikan bool. Menggunakan kompiler C ++ 20 saya mendapatkan output berikut untuk kode:
sumber
Alasan lain adalah bahwa hal itu akan memberikan kesan yang salah kepada programmer bahwa std :: set adalah himpunan dalam pengertian teori himpunan matematika. Jika mereka mengimplementasikannya, maka banyak pertanyaan lain akan mengikuti: jika sebuah std :: set memiliki berisi () untuk sebuah nilai, mengapa ia tidak memilikinya untuk set lain? Di mana union (), intersection () dan operasi dan predikat himpunan lainnya?
Jawabannya adalah, tentu saja, beberapa operasi himpunan sudah diimplementasikan sebagai fungsi di (std :: set_union () dll.) Dan lainnya diimplementasikan semudah berisi (). Fungsi dan objek fungsi bekerja lebih baik dengan abstraksi matematika daripada anggota objek, dan mereka tidak terbatas pada jenis wadah tertentu.
Jika seseorang perlu mengimplementasikan fungsionalitas set-matematika lengkap, dia tidak hanya memiliki pilihan wadah yang mendasarinya, tetapi juga dia memiliki pilihan detail implementasi, misalnya, apakah fungsi theory_union () -nya akan berfungsi dengan objek yang tidak dapat diubah, lebih cocok untuk pemrograman fungsional , atau apakah itu akan memodifikasi operannya dan menghemat memori? Apakah ini akan diimplementasikan sebagai objek fungsi dari awal atau akan lebih baik jika diimplementasikan adalah fungsi-C, dan gunakan std :: function <> jika diperlukan?
Seperti sekarang, std :: set hanyalah sebuah wadah, cocok untuk implementasi himpunan dalam pengertian matematika, tetapi ini hampir jauh dari himpunan teoretis seperti std :: vector dari vektor teoretis.
sumber