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


139

a const_iteratorとanの違いは何ですか?iteratorどこで使用しますか?


1
まあ、const_iteratorという名前はイテレータがconstのように聞こえますが、このイテレータが指すのは実際のconstです。
talekeDskobeDa

回答:


124

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

C ++のすべてのものと同様に、const通常のイテレータを使用する正当な理由がない限り(つまりconst、ポイントされた値を変更しないという事実を使用したい場合)、常にを優先します。


8
そうなる完璧な世界では。しかし、C ++では、constはコードを書いた人と同じくらい優れています:(
JaredPar

変更可能は非常に正当な理由で存在します。これはめったに使用されず、Google Code Searchを見ると、有効な使用のかなりの割合があるようです。キーワードは非常に強力な最適化ツールであり、削除することでconst-correctness(coughpointerscoughandcoughreferencescough)が向上するようなものではありません
coppro 08年

2
より強力なハックのようです。私がこれまでに見た「mutable」キーワードの使用のすべてのインスタンスのうち、1つを除いてすべてが、コードの記述が不十分であり、欠陥を回避するためのハックとしてミュータブルが必要であるという正確な指標でした。
John Dibling 2008年

7
長い計算の結果をconstクラス内にキャッシュするなど、正当な用途があります。一方、C ++開発の約20年で私が変更可能な変数を使用したのは、これがほぼ唯一の場合です。
オタクの頭、

const_iteratorを使用する一般的な例は、イテレータが右辺値である場合です
talekeDskobeDa '10 / 10/27

40

彼らはほとんど自明でなければなりません。イテレータがタイプ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イテレータは常に同じ要素を指すため、イテレータ自体はconstです。ただし、ポイントする要素はconstである必要はないため、ポイントする要素は変更できます。const_iteratorはconst要素を指すイテレータであるため、イテレータ自体を更新(インクリメントまたはデクリメントなど)することはできますが、ポイントする要素は変更できません。


1
「constイテレータは常に同じ要素を指します」これは誤りです。
John Dibling 2008年

2
どうして?不足しているアンダースコアに注意してください。const std :: vector <T> :: iterator型の変数とstd :: vector <T> :: const_iteratorを対比しています。前者の場合、イテレーター自体はconstなので、変更できませんが、参照する要素は自由に変更できます。
2008年

4
ああ、なるほど。はい、不足しているアンダースコアを逃しました。
John Dibling 2008年

3
@JohnDibling const iteraterとの間の微妙さを説明するために賛成const_iterator
legends2k

8

不幸なことに、STLコンテナーの多くのメソッドは、パラメーターとしてconst_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コンテナーに関してはそれほど普遍的ではありません。

ただし、boostコンテナはconst_iteratorsを使用します(例:boost :: unordered_map :: erase())。したがって、ブーストコンテナーを使用すると、「const agressive」になることができます。ところで、STLコンテナーが修正されるかどうか、いつ修正されるかは誰にもわかりますか?


1
それは意見の問題かもしれません。vectorand の場合、deque1つの要素を挿入すると、既存のすべてのイテレータが無効になりますconst。しかし、私はあなたの主張を理解しています。このような操作はconst、イテレーターではなくコンテナー性によって保護されます。また、標準のコンテナーインターフェイスにconstからnonconstの反復子変換関数がないのはなぜでしょうか。
Potatoswatter 2010

あなたは正しいPotatoswatterです。私は断定的に言っています。ランダムアクセスコンテナーとcontainer.begin()+(the_const_iterator_we_want_to_unconst – container.begin())はいずれにしてもO(1)であるというのは意見の問題です。非ランダムアクセスコンテナーに変換関数がないのも不思議ですが、おそらく正当な理由があるのでしょうか。非ランダムアクセスコンテナーの関数がconst_iteratorsを取らない理由があるかどうかを知っていますか?
マグナスアンデルモ2010

「そのようなことを言うのは、概念的にはconst違反ではないと私は思う」-これは非常に興味深いコメントであり、このトピックについて次のように考えています。単純なポインタを使用するとint const * foo; int * const foo;int const * const foo;3つすべてが有効であり、それぞれ独自の方法で有効であると言えます。 std::vector<int> const bar2番目のものと同じである必要がありますが、残念ながら3番目のように扱われることがよくあります。問題の根本的な原因は、ベクトルの場合std::vector<int const> bar;と同じ効果を得る方法がない場合に、いつだかわかりませんint const *foo;
dgnuff 2018年

5

可能な限りconst_iteratorを使用し、他に選択肢がない場合はイテレータを使用します


4

最小限の実行可能な例

非constイテレータを使用すると、ポイントする対象を変更できます。

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オーバーロードされ、コンテナ変数の定数に応じて、iteratorまたはconst_iteratorそのどちらかに応じて返されます。

const_iteratorポップアップの一般的なケースはthisconstメソッド内で使用される場合です。

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->vconstの。

通常はでそれを忘れることができますが、autoこれらのイテレータを渡し始める場合は、メソッドシグネチャについてそれらについて考える必要があります。

constおよびnon-constと同様に、非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 intvsに類似int:コンテナを変更する必要がない場合は常に使用するconstイテレータを使用して、変更せずに読み取る意図をより適切に文書化します。


0

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


0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.