Yanıtlar:
const_iterator
işaret ettikleri değerleri değiştirmenize izin vermiyor, normal iterator
s.
C ++ 'daki her şeyde olduğu gibi, const
düzenli yineleyiciler kullanmak için iyi bir neden olmadığı sürece her zaman tercih edin (yani const
, işaret edilen değeri değiştirmek zorunda olmadıklarını kullanmak istiyorsanız ).
Hemen hemen açıklayıcı olmalıdırlar. Yineleyici T türündeki bir öğeyi gösteriyorsa, const_iterator 'const T' türündeki bir öğeyi gösterir.
Temel olarak işaretçi türlerine eşdeğerdir:
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
Bir sabit yineleyici her zaman aynı öğeyi işaret eder, bu nedenle yineleyicinin kendisi sabittir. Ancak, işaret ettiği öğenin const olması gerekmez, bu nedenle işaret ettiği öğe değiştirilebilir. Bir const_iterator, bir const öğesine işaret eden bir yineleyicidir, bu nedenle yineleyicinin kendisi güncellenebilirken (örneğin artırılabilir veya azaltılabilir), işaret ettiği öğe değiştirilemez.
const iterater
ve arasındaki inceliği açıkladığı için seçildi const_iterator
.
Ne yazık ki, STL kapları için birçok yöntem const_iterators yerine yineleyicileri parametre olarak alır . Bir const_iterator'ınız varsa, "bu yineleyicinin işaret ettiği öğeden önce bir öğe ekleyin" diyemezsiniz (bence böyle bir şey kavramsal olarak bir const ihlali değildir). Yine de bunu yapmak istiyorsanız, std :: advance () veya boost :: next () kullanarak sabit olmayan bir yineleyiciye dönüştürmeniz gerekir . Örneğin. boost :: next (container.begin (), std :: distance (container.begin (), the_const_iterator_we_want_to_unconst)) . Eğer kap bir olan std :: liste , daha sonra bu çağrı için çalışma süresi olacak O (n) .
Bu nedenle, "mantıklı" olan her yerde const eklemek için evrensel kural, STL kapları söz konusu olduğunda daha az evrenseldir.
Bununla birlikte, destek kapları const_iterators alır (örn. Boost :: unordered_map :: erase ()). Yani takviye kapları kullandığınızda "const agresif" olabilirsiniz. Bu arada, STL kaplarının sabitlenip sabitlenmeyeceğini veya ne zaman sabitleneceğini bilen var mı?
vector
ve deque
bir eleman geçersiz çok değil tüm mevcut yineleyicinızı, ekleme, const
. Ama ne demek istediğini anlıyorum. Bu tür işlemler const
yineleyiciler tarafından değil, konteyner tarafından korunur . Ve neden standart konteyner arayüzünde bir const-non-const yineleyici dönüşüm fonksiyonu olmadığını merak ediyorum.
int const * foo;
int * const foo;
ve int const * const foo;
her üçü de her biri kendi yollarıyla geçerli ve yararlıdır. std::vector<int> const bar
ikincisi ile aynı olmalıdır, ancak maalesef genellikle üçüncü gibi tedavi edilir. Sorunun temel nedeni, bir vektördeki ile std::vector<int const> bar;
aynı etkiyi elde etmenin bir yolu olmadığı anlamına int const *foo;
gelemediğimizdir.
Minimal çalıştırılabilir örnekler
Sabit olmayan yineleyiciler işaret ettiklerini değiştirmenize olanak tanır:
std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);
Const yineleyicileri şunları yapmaz:
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;
Yukarıda gösterildiği gibi, v.begin()
bir const
aşırı ve döner ya iterator
ya da const_iterator
kap değişkeninin const-lik bağlı olarak:
const_iterator
Açılan yaygın bir durum this
, bir const
yöntemin içinde kullanıldığı zamandır :
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
this
const yapar , bu da this->v
const yapar .
Genellikle bunu unutabilirsiniz auto
, ancak bu yineleyicileri geçmeye başlarsanız, yöntem imzaları için bunları düşünmeniz gerekir.
Const ve const olmayanlara benzer şekilde, const olmayanlardan const'a kolayca dönüştürebilirsiniz, ancak bunun tersi olmaz:
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;
Hangisinin kullanmak için: analog için const int
vs int
: const yineleyicinızı tercih bunları kullanabilirsiniz zaman (onlarla kabı değiştirmeye gerek yoktur olduğunda), daha iyi belgeye değiştirmeden okuma niyetinizi.
(diğerlerinin söylediği gibi) const_iterator, işaret ettiği öğeleri değiştirmenize izin vermez, bu const sınıfı yöntemlerinin içinde yararlıdır. Ayrıca niyetinizi ifade etmenizi sağlar.
Tamam Sabit yineleyici kullanmadan önce çok basit bir örnekle açıklayayım. Rasgele tamsayı koleksiyonu "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;
Koleksiyon içinde veri yazmak / düzenlemek için görüldüğü gibi normal yineleyici kullanılır, ancak okuma amacıyla sabit yineleyici kullanılmıştır. Döngü için önce sabit yineleyici kullanmayı denerseniz hata alırsınız. Temel kural olarak, toplama içindeki verileri okumak için sürekli yineleyici kullanın.