const_iterator
とiterator
の違いは何ですか。また、どこでどちらを使用しますか?
const_iterator
sでは、それらが指す値を変更することはできませんが、通常のiterator
sではできます。
C++のすべてのものと同様に、通常の反復子を使用する正当な理由がない限り、常にconst
を優先します(つまり、const
ではないという事実を使用して、指示先を変更します)値)。
彼らはほとんど自明であるべきです。反復子がT型の要素を指す場合、const_iteratorは 'const T'型の要素を指します。
基本的にはポインタ型と同等です:
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
Constイテレータは常に同じ要素を指すため、イテレータitselfはconstです。ただし、それが指す要素はconstである必要はないため、指す要素は変更できます。 const_iteratorはconst要素を指す反復子であるため、反復子自体は更新(たとえば、インクリメントまたはデクリメント)できますが、指す要素は変更できません。
残念ながら、STLコンテナの多くのメソッドは、パラメーターとしてconst_iteratorsではなくiteratorsを使用します。 const_iteratorがある場合、「このイテレータが指す要素の前に要素を挿入する」と言うことはできません(私の意見では、そのようなことは概念的にはconst違反ではありません)。とにかくそれをしたい場合は、std :: advance()またはboost :: next()を使用して非constイテレータに変換する必要があります。例えば。 boost :: next(container.begin()、std :: distance(container.begin()、the_const_iterator_we_want_to_unconst))コンテナがstd :: listの場合、その呼び出しの実行時間はO(n)になります。
したがって、constを「論理的」に追加する普遍的なルールは、STLコンテナに関してはあまり一般的ではありません。
ただし、ブーストコンテナはconst_iteratorを使用します(例:boost :: unordered_map :: erase())。したがって、ブーストコンテナを使用すると、「コンストアグレッシブ」になります。ところで、STLコンテナが修正されるかどうか、またはいつ修正されるかは誰にもわかりませんか?
可能な場合はconst_iteratorを使用し、他に選択肢がない場合はiteratorを使用します。
最小限の例
非定数反復子を使用すると、それらが指すものを変更できます。
_std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);
_
定数反復子はしません:
_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;
_
上記のように、v.begin()
はconst
オーバーロードされ、コンテナ変数のconst-nessに応じてiterator
または_const_iterator
_のいずれかを返します。
_const_iterator
_がポップアップする一般的なケースは、this
メソッド内でconst
が使用される場合です。
_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を作成し、これは_this->v
_ constを作成します。
通常はauto
でそれを忘れることができますが、これらのイテレータを渡し始める場合は、メソッドシグネチャについてそれらについて考える必要があります。
Constやnon-constと同様に、non-constからconstに簡単に変換できますが、その逆はできません。
_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;
_
どちらを使用するか:_const int
_ vs int
に類似:読み取りの意図をより適切に文書化するために、使用できる場合はいつでも(イテレーターを使用してコンテナーを変更する必要がない場合)constイテレーターを優先します変更せずに。
okまず、定数イテレータを使用せずに、非常に簡単な例で説明します。ランダムな整数コレクション「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;
コレクション内のデータの書き込み/編集には通常のイテレータが使用されていますが、読み取りには定数イテレータが使用されています。最初にforループで定数イテレータを使用しようとすると、エラーが発生します。経験則として、定数イテレータを使用してコレクション内のデータを読み取ります。
(他の人が言ったように)const_iteratorは、それが指す要素を変更することを許可しません。これはconstクラスメソッドの内部で役立ちます。また、意図を表現することもできます。