Saya memiliki kelas wadah kustom yang ingin saya tulis iterator
dan const_iterator
kelasnya.
Saya tidak pernah melakukan ini sebelumnya dan saya gagal menemukan cara yang tepat. Apa pedoman tentang pembuatan iterator, dan apa yang harus saya ketahui?
Saya juga ingin menghindari duplikasi kode (saya merasakannya const_iterator
dan iterator
berbagi banyak hal; haruskah satu subklas yang lain?).
Catatan kaki: Saya yakin Boost memiliki sesuatu untuk meringankan ini tetapi saya tidak dapat menggunakannya di sini, karena banyak alasan bodoh.
c++
iterator
const-iterator
sebelum
sumber
sumber
Jawaban:
std::iterator
denganrandom_access_iterator_tag
. Kelas dasar ini mendefinisikan semua definisi tipe yang diperlukan oleh STL dan melakukan pekerjaan lain.Untuk menghindari duplikasi kode, kelas iterator harus berupa kelas templat dan ditentukan oleh "tipe nilai", "tipe pointer", "tipe referensi" atau semuanya (tergantung pada implementasi). Sebagai contoh:
Perhatikan
iterator_type
danconst_iterator_type
ketik definisi: mereka adalah tipe untuk non-const dan constator Anda.Lihat Juga: referensi perpustakaan standar
EDIT:
std::iterator
sudah tidak digunakan lagi sejak C ++ 17. Lihat diskusi terkait di sini .sumber
random_access_iterator
tidak dalam standar dan jawabannya tidak menangani konversi yang bisa berubah ke const. Anda mungkin ingin mewarisi, misalnyastd::iterator<random_access_iterator_tag, value_type, ... optional arguments ...>
.RefType operator*() { ... }
, saya selangkah lebih dekat - tetapi itu tidak membantu, karena saya masih membutuhkannyaRefType operator*() const { ... }
.std::iterator
adalah diusulkan untuk bantahan di C ++ 17 .std::iterator
telah ditinggalkanSaya akan menunjukkan kepada Anda bagaimana Anda dapat dengan mudah mendefinisikan iterator untuk wadah khusus Anda, tetapi untuk berjaga-jaga jika saya telah membuat pustaka c ++ 11 yang memungkinkan Anda untuk membuat iterator khusus dengan perilaku khusus untuk semua jenis wadah, berdekatan atau tidak berdampingan.
Anda dapat menemukannya di Github
Berikut adalah langkah-langkah sederhana untuk membuat dan menggunakan iterator khusus:
typedef blRawIterator< Type > iterator;
typedef blRawIterator< const Type > const_iterator;
iterator begin(){return iterator(&m_data[0]);};
const_iterator cbegin()const{return const_iterator(&m_data[0]);};
Akhirnya, ke mendefinisikan kelas iterator khusus kami:
CATATAN: Saat mendefinisikan iterator khusus, kami berasal dari kategori iterator standar untuk memberi tahu algoritme STL tentang jenis iterator yang kami buat.
Dalam contoh ini, saya mendefinisikan iterator akses acak dan iterator akses acak terbalik:
Sekarang di suatu tempat di kelas wadah khusus Anda:
sumber
m_data[m_size]
adalah UB. Anda bisa memperbaikinya dengan menggantinya denganm_data+m_size
. Untuk iterator terbalik, keduanyam_data[-1]
danm_data-1
tidak benar (UB). Untuk memperbaiki reverse_iterators Anda perlu menggunakan "pointer ke trik elemen berikutnya".Mereka sering lupa yang
iterator
harus masukconst_iterator
tetapi tidak sebaliknya. Ini cara untuk melakukannya:Dalam pemberitahuan di atas cara
IntrusiveSlistIterator<T>
konversi keIntrusiveSlistIterator<T const>
. JikaT
sudahconst
konversi ini tidak pernah digunakan.sumber
const
ke non-const
.IntrusiveSlistIterator<T const, void>::operator IntrusiveSlistIterator<T const, void>() const
?enable_if
mungkin memperbaikinya, tapi ...Boost memiliki sesuatu untuk membantu: perpustakaan Boost.Iterator.
Lebih tepatnya halaman ini: boost :: iterator_adaptor .
Yang sangat menarik adalah Contoh Tutorial yang memperlihatkan implementasi lengkap, dari awal, untuk jenis kustom.
Poin utama, seperti yang telah dikutip, adalah menggunakan implementasi template tunggal dan
typedef
itu.sumber
// a private type avoids misuse
enabler
tidak pernah dimaksudkan untuk menjadi penyedia oleh penelepon, jadi dugaan saya adalah mereka menjadikannya pribadi untuk menghindari orang yang secara tidak sengaja berusaha melewatinya. Saya tidak berpikir, begitu saja, bahwa itu dapat menciptakan masalah untuk benar-benar melewatinya, karena perlindungan ada di dalamnyaenable_if
.Saya tidak tahu apakah Boost memiliki sesuatu yang akan membantu.
Pola pilihan saya sederhana: ambil argumen templat yang sama dengan
value_type
, baik konst kualifikasi atau tidak. Jika perlu, juga jenis simpul. Lalu, yah, semua jenis jatuh ke tempatnya.Hanya ingat untuk parameterize (template-ize) semua yang perlu, termasuk copy constructor dan
operator==
. Untuk sebagian besar, semantikconst
akan menciptakan perilaku yang benar.sumber
cur
dari iterator yang berlawanan. Solusi yang muncul di benak saya adalahfriend my_container::const_iterator; friend my_container::iterator;
, tapi saya tidak berpikir itulah yang saya lakukan sebelumnya ... pokoknya garis besar umum ini berfungsi.friend class
dalam kedua kasus.Ada banyak jawaban bagus tapi saya membuat tajuk templat yang saya gunakan yang cukup ringkas dan mudah digunakan.
Untuk menambahkan iterator ke kelas Anda, hanya perlu menulis kelas kecil untuk mewakili keadaan iterator dengan 7 fungsi kecil, yang 2 di antaranya opsional:
Kemudian Anda dapat menggunakannya seperti yang Anda harapkan dari iterator STL:
Saya harap ini membantu.
sumber