Apa perbedaan antara a const_iteratordan an iteratordan di mana Anda akan menggunakan salah satunya?
Jawaban:
const_iterators tidak mengizinkan Anda untuk mengubah nilai yang mereka tunjuk, iterators biasa .
Seperti semua hal di C ++, selalu lebih disukai const, kecuali ada alasan bagus untuk menggunakan iterator biasa (yaitu Anda ingin menggunakan fakta bahwa mereka tidak constmengubah nilai menunjuk ke).
Mereka seharusnya sudah cukup jelas. Jika iterator menunjuk ke elemen tipe T, maka const_iterator menunjuk ke elemen tipe 'const T'.
Ini pada dasarnya setara dengan jenis penunjuk:
T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator
Iterator const selalu menunjuk ke elemen yang sama, jadi iterator itu sendiri adalah const. Tetapi elemen yang dituju tidak harus konstan, jadi elemen yang dituju dapat diubah. Const_iterator adalah iterator yang menunjuk ke elemen const, jadi meskipun iterator itu sendiri dapat diperbarui (bertambah atau dikurangi, misalnya), elemen yang ditunjuknya tidak dapat diubah.
const iteraterdan const_iterator.
Sayangnya, banyak metode untuk kontainer STL yang menggunakan iterator daripada const_iterators sebagai parameter. Jadi jika Anda memiliki sebuah const_iterator , Anda tidak dapat mengatakan "masukkan elemen sebelum elemen yang ditunjukkan oleh iterator ini" (mengatakan hal seperti itu secara konseptual bukanlah pelanggaran const, menurut saya). Jika Anda tetap ingin melakukannya, Anda harus mengubahnya menjadi iterator non-const menggunakan std :: advance () atau boost :: next () . Misalnya. boost :: next (container.begin (), std :: distance (container.begin (), the_const_iterator_we_want_to_unconst)) . Jika container adalah std :: list , maka waktu berjalan untuk panggilan tersebut adalah O (n) .
Jadi aturan universal untuk menambahkan const di mana pun "logis" untuk melakukannya, kurang universal dalam hal penampung STL.
Namun, penampung boost mengambil const_iterators (mis. Boost :: unordered_map :: erase ()). Jadi, saat Anda menggunakan penampung peningkat, Anda bisa menjadi "konstan agresif". Ngomong-ngomong, apakah ada yang tahu jika atau kapan kontainer STL akan diperbaiki?
vectordan deque, memasukkan satu elemen membatalkan semua iterator yang ada, yang sebenarnya tidak terlalu const. Tapi saya mengerti maksud Anda. Operasi semacam itu dilindungi oleh container const-ness, bukan iterator. Dan saya bertanya-tanya mengapa tidak ada fungsi konversi iterator const-to-nonconst di antarmuka penampung standar.
int const * foo; int * const foo;dan int const * const foo;ketiganya valid dan berguna, masing-masing dengan caranya sendiri. std::vector<int> const barharus sama dengan yang kedua, tetapi sayangnya sering diperlakukan seperti yang ketiga. Akar penyebab masalahnya adalah kita tidak bisa mengatakan std::vector<int const> bar;kapan berarti tidak ada cara untuk mendapatkan efek yang sama seperti int const *foo;pada vektor.
Contoh minimal runnable
Iterator non-const memungkinkan Anda mengubah apa yang mereka tunjuk:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);
Iterator konstan tidak:
const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
Seperti ditunjukkan di atas, v.begin()adalah constkelebihan beban, dan kembali baik iteratoratau const_iteratortergantung pada const-ness variabel wadah:
Kasus umum di mana const_iteratorpops up adalah ketika thisdigunakan di dalam constmetode:
class C {
public:
std::vector<int> v;
void f() const {
std::vector<int>::const_iterator it = this->v.begin();
}
void g(std::vector<int>::const_iterator& it) {}
};
constmembuat thisconst, yang membuat this->vconst.
Anda biasanya dapat melupakannya dengan auto, tetapi jika Anda mulai meneruskan iterator tersebut, Anda perlu memikirkannya untuk tanda tangan metode.
Sama seperti const dan non-const, Anda dapat mengonversi dengan mudah dari non-const ke const, tetapi tidak sebaliknya:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
// non-const to const.
std::vector<int>::const_iterator cit = it;
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;
// Compile time error: no conversion from const to no-const.
//it = ci1;
Yang mana yang akan digunakan: analogi dengan const intvs int: prefer const iterators kapan pun Anda dapat menggunakannya (saat Anda tidak perlu memodifikasi container dengannya), untuk mendokumentasikan niat Anda membaca dengan lebih baik tanpa memodifikasi.
(seperti yang dikatakan orang lain) const_iterator tidak mengizinkan Anda memodifikasi elemen yang ditunjuknya, ini berguna di dalam metode kelas const. Ini juga memungkinkan Anda untuk mengekspresikan niat Anda.
ok Mari saya jelaskan dengan contoh yang sangat sederhana pertama tanpa menggunakan iterator konstan menganggap kami memiliki koleksi bilangan bulat acak koleksi "randomData"
for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;
Seperti yang dapat dilihat untuk menulis / mengedit data di dalam collection, iterator normal digunakan tetapi untuk tujuan membaca, iterator konstan telah digunakan. Jika Anda mencoba menggunakan iterator konstan di loop for pertama Anda akan mendapatkan kesalahan. Sebagai aturan praktis, gunakan iterator konstan untuk membaca data di dalam koleksi.