web-dev-qa-db-ja.com

C ++ STLのconst_iteratorと非constイテレーターの違いは何ですか?

const_iteratoriteratorの違いは何ですか。また、どこでどちらを使用しますか?

114
Konrad

const_iteratorsでは、それらが指す値を変更することはできませんが、通常のiteratorsではできます。

C++のすべてのものと同様に、通常の反復子を使用する正当な理由がない限り、常にconstを優先します(つまり、constではないという事実を使用して、指示先を変更します)値)。

102
Dominic Rodger

彼らはほとんど自明であるべきです。反復子が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要素を指す反復子であるため、反復子自体は更新(たとえば、インクリメントまたはデクリメント)できますが、指す要素は変更できません。

36
jalf

残念ながら、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コンテナが修正されるかどうか、またはいつ修正されるかは誰にもわかりませんか?

7
Magnus Andermo

可能な場合はconst_iteratorを使用し、他に選択肢がない場合はiteratorを使用します。

5
Naveen

最小限の例

非定数反復子を使用すると、それらが指すものを変更できます。

_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) {}
};
_

constthis 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ループで定数イテレータを使用しようとすると、エラーが発生します。経験則として、定数イテレータを使用してコレクション内のデータを読み取ります。

0
Mr Coder

(他の人が言ったように)const_iteratorは、それが指す要素を変更することを許可しません。これはconstクラスメソッドの内部で役立ちます。また、意図を表現することもできます。

0
Trey Jackson