はいそれではコンテナ用イテレータの種類について書いていきます。
前回、前々回の記事でQVector,QLindedlist,QListについて書きましたが、そのサンプル内でイテレータを使ったものがあったかと思います。Qtでは
①Javaスタイルイテレータ
②STLスタイルイテレータ
の2種類が用意されています。今回はSTLスタイルイテレータについて書いていきます。(イテレータについてはWikiでも見てください。)②STLスタイルイテレータ
C<T>::iteratorとC<T>::const_iteratorの2種類がこれに当たります。constなしが読み書きOK、const...のほうが読み込みのみという違いです。このSTLイテレータが指す要素はJavaスタイルイテレータとは違い、要素そのものを指します。以下のような感じです。
STLイテレータはC++のポインタのように使用できます。よってかなり使い易いです。
それではサンプルを書いていきます。(C++ GUI Programming with Qt4 256ページを参考)
いつものようにQtCreaterの使用を前提とします。(QtCreaterなどの使い方は ”Qtをはじめよう" を見てください。)
ではコードを
(C<T>::const_iteratorのサンプル ※読み込みのみ)
QList<QString> list; list << "One!" << "Two!" << "T"; QList<QString>::const_iterator i = list.begin(); bool T_exist = false;//"T"が含まれているかどうかのフラグ while(i != list.end())//iが最後のうしろ以外ならループ { if(*i == "T") { T_exist = true; break; } i++;//次の要素へ } //最終的にT_existにはtrueが入ります。
はい簡単ですね。流れはlistのSTLのconstイテレータを取り出し、"T"が含まれているか走査しているだけです。
begin()やend()はSTLスタイルイテレータを返します。(リファレンス)
beginは最初の要素、endは最後の後ろの要素を指します。
(C<T>::iteratorサンプル ※読み書きOK)
QList<QString> list; list << "One!" << "Two!" << "T"; QList<QString>::iterator i = list.begin(); while(i != list.end()) { if(*i == "T")//"T"の値ならば↓ { *i = "Three!";//"Three!"に書き換え break; } i++; } //最終的にlistは[ "One!", "Two!", "Three!" ]となる
これも簡単ですね。実際はこちらのほうをよく使うと思います。流れはlistのSTLイテレータを取り出し、"T"が含まれているか走査して、あればその指し示す要素を"Three!"に書き換えているだけです。
(その他の詳細についてはリファレンスを参照してみてください。)
なお、Qtでコンテナクラスを返す関数がありますが、以下のように
//このコードは危険 QList<int>::const_iterator i = splitter->sizes().begin(); while (i != splitter->sizes().end()) { //... ++i; } //このコードは危険
のようアクセスするのはマズイようです。どうもループの先頭でsize()を呼んだ際にリストが自動で消去されイテレータの宙ぶらりんの参照先が残ってしまうからだそうです。しかも悪いことにループを実行するたびsplitter->sizes().end()を呼び出すので、そのループのたびにリストの新しいコピーを生成してしまうことになるそうです。なんだか要素が多いときを考えるとゾッとしますね。
これを避けるには以下のように
QList<int> list = splitter->sizes();//listにコピー QList<int>::const_iterator i = list.begin(); while (i != list.end()) { //... ++i; } //これは安全
必ず返されたコンテナクラスをコピーしてから反復処理を開始すれば安全だそうです。(C++ GUI Programming with Qt4 257ページに詳細が書かれています。)
以上です。