2016-07-01 3 views
6

C++では、InputIterators、ForwardIterators、BidirectionalIteratorsを比較するのに '>'または '<'を使用できないのはなぜですか?ただし、RandomAccessIteratorsを '>'または '<'と比較することができます(例:std :: vector)。これの背後にある理由は何ですか?C++イテレータに関する質問

また、なぜイテレータのコンテンツを再生できないのですか? 「cout < < itr < < endl;動作しません。これの背後にある理由は何ですか?イテレータはポインタによく似ていますが、ポインタを使うことはできますが、イテレータは使用できません。なぜですか?

一般に、イテレータとポインタの本質的な違いは何ですか?以前は似ていると思っていましたが、C++を理解する次のレベルに到達するためには、これを理解しなければならないと思います。

質問#2:すばらしい答えをいただきありがとうございます。イテレータに関してもう1つ質問があります。 イテレータが範囲外になると、C++が "50397953"のようなものを出力するのはなぜですか? NULLや '\ 0'のようなものを出力してはいけませんか?

+0

2つのフォワードイテレータに対して 'itr1 Beta

+0

ありがとうベータ。これは自然な答えです! – Thenewstockton

答えて

5

std::list<T>には双方向の反復子があり、それらを比較可能にすることは意味をなさない。このような要件に準拠するためには、std::list<T>を実装することがどのように可能であるかは明らかではありません。しかし、ランダムアクセス反復子は減算をサポートしているので、それらを比較できることは明らかです。

イテレータの値を印刷できないのはなぜですか?一般的に、そのような操作をサポートするかどうかは作者次第です。多くのイテレータは基本的にポインタの周りのポインタまたはラッパーとして実装されています---それらのためにoperator<<を指定すると、指し示されたオブジェクトのアドレスを単に出力するだけでは得られない利点はありません。

イテレータとポインタの違いについては、オブジェクトへのポインタは特定の種類のランダムアクセスイテレータですが、イテレータはイテレータの要件を満たしていればクラス型でもかまいません。

+0

ブライアンに感謝します。しかし、なぜオペレータを提供しないだろう<<ユーザーに何か利益を与えるか?プログラマーが常に調べているメモリアドレスではないのですか? – Thenewstockton

+2

@Thenewstocktonもしあなたがそれを望むのであれば、 'std :: cout <<&* it'とすることができます。私の経験では、省略形を提供するのに十分な頻度ではありません。 – Brian

+0

@Thenewstocktonは私の経験では、別注のイテレータのオペレータオーバーロードを提案するようなことをしている間は、長期的にもっと有用なように思えることがよくあります。これは、あなたが追加する戦術的な構文上の革新が、イテレータの慣習のセマンティック戦略に反して作用するからです。イテレータの概念には構文の追加がほとんどありません(http://en.cppreference.com/w/cpp/iterator )私の意見では、上で言及されているように、 "ポインタの一般化"である包括的な概念に反する作業をしないでください。基本的に。 – fish2000

3

厳密で正式な説明と実用的な説明があります。

厳密で正式な説明

これはC++での指定方法です。

ベクトル実用的な説明は常に定義することによって、連続したメモリに格納されます。イテレータは、多かれ少なかれポインタです。したがって、実際の基礎となるメモリアドレスを比較することによって、他のポインタよりも「少ない」または「大きい」ポインタを定義することが可能になります。

一方、リスト内の各要素またはセットは、どこにでも格納できます。各要素は個別にインスタンス化されます。リスト内のある特定の要素のイテレータは、同じリスト内の別の要素の異なるイテレータよりも数値的に小さいメモリ位置を参照することができますが、実際の要素は実際のリストの他の要素の後にある可能性があります。リスト内に2つのイテレータがあると、リストの最初または最後にどちらが近いかはすぐには判断できません。リストの要素を挿入して削除しても、リストの各要素は個別にインスタンス化されるため、既存のリストイテレータは無効になりません。

std::ostreamoperator<<のイテレータを使用できない実用的な理由は、もちろんこのオーバーロードが定義されていないためです。

cout << &*itr << endl; 

これは、参照される要素の実際のメモリアドレスをフォーマットします:あなたはいつもの代わりに、次の手順を実行できることに注意してください。とにかくこれは疑わしい使用です。それはほとんど無意味です。

+0

Thanks Sam。しかし、なぜSTLは過負荷を定義しないでしょうか?私は&* itrを使ってアドレスを出力することができます。しかし、「cout << itr << endl;」をサポートするのは当然のことではありません。 ?私はそれがポインタとイテレータの違いと関係していると思いますが、なぜそれほどわかりませんか?助けてください! – Thenewstockton

+0

@Tewewstockton:なぜそれは自然だろうと思いますか?私にはそう思わない。 –

+0

@BenjaminLindleyまあ、これは私が考えていることです: "cout << ptr << end;だから、 "cout << itr << endl;するのは当然ですしかしこれはうまくいかないでしょう。 – Thenewstockton

1

あなたの質問の最初の部分は私が言ったことに同意するので、私は答えませんが、私はあなたにいくつかの詳細を加えて他の2つの部分に答えます。私は説明するのが最も簡単な部分から始めています。

一般に、イテレータとポインタの本質的な違いは何ですか?以前は似ていると思っていましたが、C++を理解する次のレベルに到達するためには、これを理解しなければならないと思います。

イテレータはポインタの一般化です。

あなたはまた、また、そのiterator implementation on github

で見ることができ、なぜ私たちは、イテレータのコンテンツをCOUTできないのですか? 「cout < < itr < < endl;動作しません。これの背後にある理由は何ですか?イテレータはポインタによく似ていますが、ポインタを使うことはできますが、イテレータは使用できません。なぜですか?

私は理解しているように、イテレータはアイテムへのポインタを格納するフィールドを持つクラスです。 '*'演算子は上書きされ、ポインタアドレスに格納されている値を返します。