Ambil dua baris kode berikut:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
Dan ini:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
Saya diberitahu bahwa cara kedua lebih disukai. Kenapa ini?
some_iterator++
ke++some_iterator
. Pasca-kenaikan menciptakan iterator sementara yang tidak perlu.end()
memasukkan klausa deklarasi.vector::end
mungkin memiliki masalah yang lebih buruk untuk dikhawatirkan daripada apakah itu diangkat dari loop atau tidak. Secara pribadi saya lebih suka kejelasan - jika itu adalah panggilan untukfind
dalam kondisi terminasi saya khawatir.it != vec.end()
danit != end
, itu antara(vector<T>::iterator it = vec.begin(); it != vec.end(); ++it)
dan(vector<T>::iterator it = vec.begin(), end = vec.end(); it != end; ++it)
. Saya tidak perlu menghitung karakter. Dengan segala cara lebih suka satu daripada yang lain, tetapi ketidaksepakatan orang lain dengan preferensi Anda bukanlah "kecerobohan", itu adalah preferensi untuk kode yang lebih sederhana dengan variabel yang lebih sedikit dan dengan demikian lebih sedikit dipikirkan saat membacanya.Jawaban:
Bentuk pertama efisien hanya jika vector.size () adalah operasi cepat. Ini berlaku untuk vektor, tetapi tidak untuk daftar, misalnya. Juga, apa yang Anda rencanakan untuk dilakukan di dalam tubuh loop? Jika Anda berencana mengakses elemen seperti pada
maka Anda membuat asumsi bahwa wadah telah
operator[](std::size_t)
ditentukan. Sekali lagi, ini berlaku untuk vektor tetapi tidak untuk wadah lain.Penggunaan iterator membawa Anda lebih dekat ke kemandirian wadah . Anda tidak membuat asumsi tentang kemampuan akses acak atau
size()
operasi cepat , hanya saja wadah tersebut memiliki kemampuan iterator.Anda dapat meningkatkan kode Anda lebih lanjut dengan menggunakan algoritma standar. Bergantung pada apa yang ingin Anda capai, Anda dapat memilih untuk menggunakannya
std::for_each()
,std::transform()
dan seterusnya. Dengan menggunakan algoritme standar dan bukannya perulangan eksplisit, Anda menghindari menciptakan kembali roda. Kode Anda cenderung lebih efisien (mengingat algoritma yang tepat dipilih), benar dan dapat digunakan kembali.sumber
size_t
variabel anggotasize()
.size()
fungsi anggota akan diharuskan memiliki kompleksitas waktu yang konstan untuk semua kontainer yang mendukungnya, termasukstd::list
.Ini adalah bagian dari proses indoktrinasi C ++ modern. Iterator adalah satu-satunya cara untuk mengulang sebagian besar wadah, sehingga Anda menggunakannya bahkan dengan vektor hanya untuk membuat Anda masuk ke pola pikir yang tepat. Serius, itulah satu-satunya alasan saya melakukannya - saya tidak berpikir saya pernah mengganti vektor dengan jenis wadah yang berbeda.
Wow, ini masih diturunkan setelah tiga minggu. Kurasa tidak ada gunanya sedikit bicara.
Saya pikir indeks array lebih mudah dibaca. Ini cocok dengan sintaks yang digunakan dalam bahasa lain, dan sintaksis yang digunakan untuk array C kuno. Itu juga kurang verbose. Efisiensi harus menjadi pencuci jika kompiler Anda bagus, dan hampir tidak ada kasus di mana itu penting.
Meski begitu, saya masih menemukan diri saya sering menggunakan iterator dengan vektor. Saya percaya iterator adalah konsep penting, jadi saya mempromosikannya kapan saja saya bisa.
sumber
karena Anda tidak mengikat kode Anda dengan implementasi tertentu dari daftar some_vector. jika Anda menggunakan indeks array, harus berupa array; jika Anda menggunakan iterator Anda dapat menggunakan kode itu pada implementasi daftar apa pun.
sumber
Bayangkan some_vector diimplementasikan dengan daftar tertaut. Kemudian meminta item di tempat ke-i mengharuskan operasi saya harus dilakukan untuk melintasi daftar node. Sekarang, jika Anda menggunakan iterator, secara umum, itu akan melakukan upaya terbaik untuk menjadi seefisien mungkin (dalam kasus daftar tertaut, itu akan mempertahankan pointer ke node saat ini dan memajukannya di setiap iterasi, hanya membutuhkan operasi tunggal).
Jadi itu menyediakan dua hal:
sumber
Aku akan menjadi pendukung setan di sini, dan tidak merekomendasikan iterator. Alasan utama mengapa, adalah semua kode sumber yang telah saya kerjakan mulai dari pengembangan aplikasi Desktop hingga pengembangan game apakah saya juga tidak perlu menggunakan iterators. Setiap saat mereka tidak diperlukan dan kedua asumsi tersembunyi dan kekacauan kode dan debugging mimpi buruk yang Anda dapatkan dengan iterator menjadikannya contoh utama untuk tidak menggunakannya dalam aplikasi apa pun yang membutuhkan kecepatan.
Bahkan dari sudut pandang maintence mereka berantakan. Itu bukan karena mereka tetapi karena semua alias yang terjadi di belakang layar. Bagaimana saya tahu bahwa Anda belum mengimplementasikan daftar vektor atau array virtual Anda sendiri yang melakukan sesuatu yang sama sekali berbeda dengan standar. Apakah saya tahu jenis apa yang sekarang saat runtime? Apakah Anda membebani operator saya tidak punya waktu untuk memeriksa semua kode sumber Anda. Apa saya tahu versi STL yang Anda gunakan?
Masalah berikutnya yang Anda dapatkan dengan iterator adalah abstraksi yang bocor, meskipun ada banyak situs web yang membahas hal ini secara terperinci dengan mereka.
Maaf, saya belum dan masih belum melihat titik di iterator. Jika mereka abstrak daftar atau vektor dari Anda, padahal sebenarnya Anda harus sudah tahu apa vektor atau daftar berurusan dengan Anda jika Anda tidak maka Anda hanya akan mengatur diri sendiri untuk beberapa sesi debug hebat di masa depan.
sumber
Anda mungkin ingin menggunakan iterator jika Anda ingin menambah / menghapus item ke vektor saat Anda mengulanginya.
Jika Anda menggunakan indeks, Anda harus mengacak item naik / turun di array untuk menangani penyisipan dan penghapusan.
sumber
std::list
dibandingkan denganstd::vector
, jika Anda merekomendasikan menggunakan daftar-tertaut alih-alih astd::vector
. Lihat Halaman 43: ecn.channel9.msdn.com/events/GoingNative12/GN12Cpp11Style.pdf Dalam pengalaman saya, saya menemukanstd::vector
lebih cepat daripadastd::list
bahkan jika saya mencari semua itu dan menghapus elemen di posisi sewenang-wenang.for (node = list->head; node != NULL; node = node->next)
pendek dari dua baris kode Anda yang disatukan (deklarasi dan loop head). Jadi saya katakan lagi - tidak ada perbedaan mendasar dalam singkatnya antara menggunakan iterator dan tidak menggunakannya - Anda masih harus memenuhi tiga bagian darifor
pernyataan, bahkan jika Anda menggunakanwhile
: menyatakan, beralih, periksa penghentian.Pemisahan Kekhawatiran
Sangat bagus untuk memisahkan kode iterasi dari perhatian 'inti' dari loop. Ini hampir merupakan keputusan desain.
Memang, pengulangan dengan indeks mengikat Anda ke implementasi wadah. Meminta wadah untuk memulai dan mengakhiri iterator, memungkinkan kode loop untuk digunakan dengan jenis wadah lainnya.
Juga, di
std::for_each
jalan, Anda MEMBERITAHU koleksi apa yang harus dilakukan, bukannya MEMINTA sesuatu tentang internalStandar 0x akan memperkenalkan penutupan, yang akan membuat pendekatan ini jauh lebih mudah digunakan - lihatlah kekuatan ekspresif eg Ruby
[1..6].each { |i| print i; }
...Performa
Tapi mungkin masalah yang paling diawasi adalah bahwa, dengan menggunakan
for_each
pendekatan ini menghasilkan peluang untuk membuat iterasi diparalelkan - blok threading intel dapat mendistribusikan blok kode pada jumlah prosesor dalam sistem!Catatan: setelah menemukan
algorithms
perpustakaan, dan terutamaforeach
, saya melewati dua atau tiga bulan menulis struct operator 'pembantu' yang sangat kecil yang akan membuat rekan pengembang Anda menjadi gila. Setelah waktu ini, saya kembali ke pendekatan pragmatis - badan lingkaran kecil tidak layakforeach
lagi :)Referensi yang harus dibaca tentang iterator adalah buku "Extended STL" .
GoF memiliki paragraf kecil kecil di akhir pola Iterator, yang berbicara tentang merek iterasi ini; itu disebut 'iterator internal'. Lihat di sini juga.
sumber
Karena lebih berorientasi objek. jika Anda mengulangi dengan indeks Anda mengasumsikan:
a) bahwa benda-benda itu dipesan
b) bahwa benda-benda itu dapat diperoleh dengan indeks
c) bahwa kenaikan indeks akan mengenai setiap item
d) bahwa indeks itu dimulai dari nol
Dengan iterator, Anda mengatakan "berikan saya segalanya sehingga saya bisa bekerja dengannya" tanpa mengetahui apa yang menjadi implementasi yang mendasarinya. (Di Jawa, ada koleksi yang tidak dapat diakses melalui indeks)
Juga, dengan iterator, tidak perlu khawatir keluar dari batas array.
sumber
Satu hal yang menyenangkan tentang iterator adalah mereka lebih memungkinkan Anda untuk mengekspresikan (dan menegakkan) preferensi konstanta Anda. Contoh ini memastikan bahwa Anda tidak akan mengubah vektor di tengah-tengah loop Anda:
sumber
const_iterator
. Jika saya mengubah vektor dalam loop, saya melakukannya karena suatu alasan, dan untuk 99,9% dari waktu itu mengubah bukanlah kecelakaan, dan untuk sisanya, itu hanya bug seperti segala jenis bug dalam kode pembuatnya perlu diperbaiki. Karena di Jawa, dan banyak bahasa lainnya, tidak ada objek const sama sekali, tetapi pengguna bahasa tersebut tidak pernah memiliki masalah tanpa dukungan const dalam bahasa tersebut.const_iterator
, lalu apa alasannya?Selain semua jawaban luar biasa lainnya ...
int
mungkin tidak cukup besar untuk vektor Anda. Sebaliknya, jika Anda ingin menggunakan pengindeksan, gunakansize_type
untuk wadah Anda:sumber
int i
kemyvector.size()
.Saya mungkin harus menunjukkan Anda juga bisa menelepon
std::for_each(some_vector.begin(), some_vector.end(), &do_stuff);
sumber
Iterator STL sebagian besar ada sehingga semacam algoritma STL bisa menjadi wadah independen.
Jika Anda hanya ingin mengulang semua entri dalam vektor, cukup gunakan gaya loop indeks.
Ini kurang mengetik dan lebih mudah diurai untuk kebanyakan manusia. Akan lebih baik jika C ++ memiliki loop foreach sederhana tanpa berlebihan dengan templat magic.
sumber
Saya tidak berpikir itu membuat banyak perbedaan untuk vektor. Saya lebih suka menggunakan indeks sendiri karena saya menganggapnya lebih mudah dibaca dan Anda dapat melakukan akses acak seperti melompat ke depan 6 item atau melompat mundur jika perlu.
Saya juga suka membuat referensi ke item di dalam loop seperti ini sehingga tidak ada banyak tanda kurung di sekitar tempat:
Menggunakan iterator bisa bagus jika Anda berpikir Anda mungkin perlu mengganti vektor dengan daftar di beberapa titik di masa depan dan juga terlihat lebih bergaya untuk STL aneh tapi saya tidak bisa memikirkan alasan lain.
sumber
I prefer to use an index myself as I consider it to be more readable
hanya dalam beberapa situasi; di negara lain, indeks dengan cepat menjadi sangat berantakan.and you can do random access
yang bukan fitur unik dari indeks sama sekali: lihat en.cppreference.com/w/cpp/concept/RandomAccessIteratorBentuk kedua mewakili apa yang Anda lakukan dengan lebih akurat. Dalam contoh Anda, Anda tidak peduli tentang nilai i, sungguh - semua yang Anda inginkan adalah elemen berikutnya di iterator.
sumber
Setelah mempelajari sedikit lebih banyak tentang masalah jawaban ini, saya menyadari itu agak terlalu menyederhanakan. Perbedaan antara loop ini:
Dan loop ini:
Cukup minim. Bahkan, sintaks melakukan loop dengan cara ini tampaknya tumbuh pada saya:
Iterator membuka beberapa fitur deklaratif yang cukup kuat, dan ketika dikombinasikan dengan perpustakaan algoritma STL Anda dapat melakukan beberapa hal keren yang berada di luar lingkup indeks array administrivia.
sumber
for (Iter it = {0}; it != end; ++it) {...}
- Anda baru saja meninggalkan deklarasi - jadi singkatnya tidak jauh berbeda dari contoh kedua Anda. Tetap, +1.Pengindeksan membutuhkan
mul
operasi ekstra . Misalnya, untukvector<int> v
, kompiler dikonversiv[i]
menjadi&v + sizeof(int) * i
.sumber
sizeof
dan hanya menambahkannya sekali per iterasi, daripada melakukan seluruh perhitungan offset lagi setiap waktu.Selama iterasi Anda tidak perlu tahu jumlah item yang akan diproses. Anda hanya perlu item dan iterator melakukan hal-hal seperti itu dengan sangat baik.
sumber
Belum ada yang menyebutkan bahwa satu keuntungan dari indeks adalah bahwa mereka tidak menjadi tidak valid ketika Anda menambahkan ke wadah yang berdekatan seperti
std::vector
, sehingga Anda dapat menambahkan item ke wadah selama iterasi.Ini juga dimungkinkan dengan iterator, tetapi Anda harus menelepon
reserve()
, dan karena itu perlu tahu berapa banyak item yang akan Anda tambahkan.sumber
Beberapa poin bagus sudah. Saya punya beberapa komentar tambahan:
Dengan asumsi kita berbicara tentang pustaka standar C ++, "vektor" menyiratkan sebuah wadah akses acak yang memiliki jaminan C-array (akses acak, tata letak memori contiguos dll). Jika Anda mengatakan 'some_container', banyak dari jawaban di atas akan lebih akurat (kemandirian wadah dll).
Untuk menghilangkan ketergantungan pada optimisasi kompiler, Anda dapat memindahkan some_vector.size () dari loop dalam kode yang diindeks, seperti:
Selalu lakukan iterator pra-kenaikan dan perlakukan post-increment sebagai kasus luar biasa.
Jadi dengan asumsi dan diindekskan
std::vector<>
seperti wadah, tidak ada alasan yang baik untuk memilih satu dari yang lain, secara berurutan melalui wadah. Jika Anda harus sering merujuk ke indeks elemnent yang lebih lama atau lebih baru, maka versi yang diindeks lebih sesuai.Secara umum, menggunakan iterator lebih disukai karena algoritma memanfaatkannya dan perilaku dapat dikontrol (dan secara implisit didokumentasikan) dengan mengubah jenis iterator. Lokasi array dapat digunakan sebagai ganti iterator, tetapi perbedaan sintaksis akan menonjol.
sumber
Saya tidak menggunakan iterator untuk alasan yang sama saya tidak suka untuk setiap pernyataan. Ketika memiliki banyak loop dalam, cukup sulit untuk melacak variabel global / anggota tanpa harus mengingat semua nilai lokal dan nama iterator juga. Apa yang menurut saya berguna adalah menggunakan dua set indeks untuk berbagai kesempatan:
Saya bahkan tidak ingin menyingkat hal-hal seperti "animation_matrices [i]" ke beberapa acak "anim_matrix" -named-iterator misalnya, karena Anda tidak dapat melihat dengan jelas dari array mana nilai ini berasal.
sumber
it
,jt
,kt
, dll atau bahkan hanya terus menggunakani
,j
,k
, dll Dan jika Anda perlu tahu persis apa yang iterator mewakili, maka saya sesuatu sepertifor (auto anim = anims.begin(); ...) for (auto anim_bone = anim->bones.begin(); ...) anim_bone->wobble()
akan lebih deskriptif daripada harus terus-menerus mengindeks sepertianimation_matrices[animIndex][boneIndex]
.for
loop berbasis rentang , yang membuat cara berbasis iterator melakukan ini bahkan lebih ringkas.Sungguh, hanya itu yang ada untuk itu. Ini bukan seolah-olah Anda akan mendapatkan lebih banyak brevity dengan cara rata-rata, dan jika brevity benar-benar tujuan Anda, Anda selalu dapat kembali ke makro.
sumber
Jika Anda memiliki akses ke fitur C ++ 11 , maka Anda juga dapat menggunakan loop berbasis rentang
for
untuk mengulangi vektor Anda (atau wadah lain) sebagai berikut:Manfaat dari loop ini adalah Anda dapat mengakses elemen-elemen vektor secara langsung melalui
item
variabel, tanpa menjalankan risiko mengacaukan indeks atau membuat kesalahan ketika mendereferensikan iterator. Selain itu, placeholderauto
mencegah Anda dari keharusan mengulangi jenis elemen wadah, yang membawa Anda lebih dekat ke solusi independen wadah.Catatan:
operator[]
ada untuk wadah Anda (dan cukup cepat untuk Anda), maka lebih baik pergi untuk cara pertama Anda.for
Lingkaran berbasis rentang tidak dapat digunakan untuk menambah / menghapus elemen ke / dari suatu wadah. Jika Anda ingin melakukan itu, maka lebih baik tetap pada solusi yang diberikan oleh Brian Matthews.const
sebagai berikut:for (auto const &item : some_vector) { ... }
.sumber
Bahkan lebih baik daripada "memberi tahu CPU apa yang harus dilakukan" (keharusan) adalah "memberi tahu perpustakaan apa yang Anda inginkan" (fungsional).
Jadi alih-alih menggunakan loop Anda harus mempelajari algoritma yang ada di stl.
sumber
Untuk kemandirian wadah
sumber
Saya selalu menggunakan indeks array karena banyak aplikasi saya memerlukan sesuatu seperti "tampilan gambar kecil gambar". Jadi saya menulis sesuatu seperti ini:
sumber
Kedua implementasinya benar, tetapi saya lebih suka loop 'for'. Karena kami telah memutuskan untuk menggunakan Vector dan bukan wadah lain, menggunakan indeks akan menjadi pilihan terbaik. Menggunakan iterator dengan Vektor akan kehilangan manfaat memiliki objek dalam blok memori kontinu yang membantu memudahkan akses mereka.
sumber
Saya merasa bahwa tidak ada jawaban di sini yang menjelaskan mengapa saya suka iterator sebagai konsep umum alih-alih pengindeksan ke dalam wadah. Perhatikan bahwa sebagian besar pengalaman saya menggunakan iterator sebenarnya tidak berasal dari C ++ tetapi dari bahasa pemrograman tingkat tinggi seperti Python.
Antarmuka iterator membebankan lebih sedikit persyaratan pada konsumen atas fungsi Anda, yang memungkinkan konsumen untuk berbuat lebih banyak dengannya.
Jika semua yang Anda butuhkan adalah dapat meneruskan-iterate, pengembang tidak terbatas menggunakan wadah yang dapat diindeks - mereka dapat menggunakan implementasi kelas apa pun
operator++(T&)
,operator*(T)
danoperator!=(const &T, const &T)
.Algoritme Anda berfungsi untuk case yang Anda butuhkan - iterasi melalui vektor - tetapi juga dapat berguna untuk aplikasi yang tidak perlu Anda antisipasi:
Mencoba menerapkan operator kurung siku yang melakukan sesuatu yang mirip dengan iterator ini akan dibuat-buat, sedangkan implementasi iterator relatif sederhana. Operator kurung kotak juga membuat implikasi tentang kemampuan kelas Anda - yang dapat Anda indeks ke titik sembarang - yang mungkin sulit atau tidak efisien untuk diterapkan.
Iterator juga cocok untuk dekorasi . Orang-orang dapat menulis iterator yang mengambil iterator di konstruktor mereka dan memperluas fungsinya:
Walaupun mainan ini mungkin tampak biasa, tidak sulit untuk membayangkan menggunakan iterator dan dekorator iterator untuk melakukan hal-hal yang kuat dengan antarmuka yang sederhana - menghias iterator hasil-hasil basis data hanya-maju dengan iterator yang membangun objek model dari hasil tunggal, misalnya . Pola-pola ini memungkinkan iterasi yang efisien-memori dari set yang tak terbatas dan, dengan filter seperti yang saya tulis di atas, berpotensi hasil evaluasi malas.
Bagian dari kekuatan template C ++ adalah antarmuka iterator Anda, ketika diterapkan pada orang-orang seperti array C panjang-tetap, meluruh ke aritmatika pointer sederhana dan efisien , menjadikannya abstraksi yang benar-benar nol biaya.
sumber