Apa perbedaan antara a const_iterator
dan an iterator
dan di mana Anda akan menggunakan salah satunya?
Jawaban:
const_iterator
s tidak mengizinkan Anda untuk mengubah nilai yang mereka tunjuk, iterator
s 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 const
mengubah 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 iterater
dan 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?
vector
dan 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 bar
harus 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 const
kelebihan beban, dan kembali baik iterator
atau const_iterator
tergantung pada const-ness variabel wadah:
Kasus umum di mana const_iterator
pops up adalah ketika this
digunakan di dalam const
metode:
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) {}
};
const
membuat this
const, yang membuat this->v
const.
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 int
vs 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.