STDのイテレータを回している時にやってはいけないこと?


堀江伸一  2011-06-02 09:27:51  No: 72699  IP: 192.*.*.*

c++のstdは便利な機能ですが、最近色々疑問がわいてきました。
例えばvectorのiteratorを回している時に要素を追加してはいけない。
とかあるようですが、他に注意する点はあるでしょうか。
回している時に要素をvectorに追加するとvectorの要素が壊れることがあるそうですがなぜ起こるのでしょうか?

質問1
setやmapのiteratorを回している時にしてはいけない事や注意点などあるのでしょうか?

質問2
queueやstackなどでも注意点はあるのでしょうか?
例えば、queueやstackにiteratorはあるのかとか、queueやstackの要素にポインタを行ったり参照したりしている時に、何かおかしなことが起きたりしますか?
mapやsetなどではどうなるのでしょうか?

質問3
set<set<int>>のような構造に対し,set<set<int>>::iterator it1,set<int> ite2 
でit1のイテレータを回している時,set<set<int>>やset<int>の要素を追加したり削除したり、it2を回している時にset<set<int>>やset<int>要素を追加したりはできるのでしょうか?
なにか落とし穴があったりしますか?
set<set<int>> aのようなデータをメモリから解放する時はa.clear()でいいのでしょうか?

set<map<int,int>>やset<queue<int>>やvector<set<int>>など色々な組み合わせが考えられますが、この時の注意点や基本的な取り扱い方などあるでしょうか?
iteratorを回してない時の追加や削除は基本的に安全に行えるのでしょうか?

質問4
そもそもiteratorとはなんなのでしょうか?
構造化されたポインタ、それと参照なのでしょうか?

編集 削除
tetrapod  2011-06-02 10:51:31  No: 72700  IP: 192.*.*.*

質問4だけ
ポインタのようなものと理解すればいい。実装を気にする必要はない。
何らかのコンテナ(データの列)と、なんちゃら iterator p; があるとき
*p で iterator が指すの要素を示す
++p で次の要素を示す iterator 値が得られる
--p で前の要素を示す iterator 値が得られる(可能なら)
ことができる、というのが iterator

「リスト」を C などで自分で実装するとわかるけど、
次の要素を示すには p->next と書くことになる。
前の要素を示すには p->prev と書くことになる。
配列の要素に対する記述方法と違うことになるので統一性がないわけだ。
これを「こう書きましょう」と決めたのが iterator

質問1−3はマニュアル/言語仕様書に全部載ってるから読んで。

編集 削除
堀江伸一  URL  2011-06-02 16:40:49  No: 72701  IP: 192.*.*.*

ずっと一人で勉強してるもので言語仕様書とかマニュアルとか何を読んだらいいかわからないのでお教えいただけたらと思います。
Web上のページ、それとも値段の高い書籍でしょうか?
MSDN等を読めばいいのでしょうか?
マニュアルが膨大すぎてどう読んだらいいのか読み方がわからない状態です。

編集 削除
επιστημη  URL  2011-06-02 19:46:11  No: 72702  IP: 192.*.*.*

かなり無茶振りではあるけども、原本はコレ↓
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3242.pdf

編集 削除
tetrapod  2011-06-03 13:11:00  No: 72703  IP: 192.*.*.*

言語規格書の draft ですな。そりゃ無茶振りすぎるっす・・・
しかも C++ 0x draft だし未来を先取りっすね。

お勉強レベルだったら規格書は要らない。でもまあほしい人向けに。

今有効なのは ISO/IEC 14882:2003 っす。
http://webstore.ansi.org/ から PDF で買える $30.00 まあこんなもんか。
日本語がよければ JIS X 3014:2003 http://www.jsa.or.jp/ から買える。
冊子で \17325- っす・・高い。検索が効かないし、俺は冊子は要らない。

---

ぱっと検索した範囲だと iterator の有効性などに触れているページは少ない感じ。
http://www.cppreference.com/wiki/jp:start
とかでも Complexity には触れているが iterator/reference については無し。
その辺は ISO/IEC 14882 のほうに分がありそう。

> マニュアルが膨大すぎてどう読んだらいいのか読み方がわからない状態です。
俺んちの後輩がこんなこと言ってたらぶっ飛ばすところだ。
マニュアル0より無限大にマシぢゃん。

iterator が無効になるならないは、コンテナの実装に大きく依存するんだが
そもそも vector や list や map って何?どういう構造?
あたりをそれなりに理解していれば、わざわざ書くまでも無く想像つくよね・・・

編集 削除
ホウジョウウサギ  2011-06-03 18:26:42  No: 72704  IP: 192.*.*.*

Webとかでもいいのかもしれないけど,
一度本屋にでも行って,STLとかC++とかに関する本でも買ってみてはいかがでしょう?
自分は  STLは
επιστημηさん監修の「STL標準講座」(\3800)を買って勉強した.
(要素の挿入や削除を行ったときにイテレータが無効になるかどうかといったことも当然触れられている.)
C++に触り始めたころに買った「effective C++」等と共に  常に見れる位置に置いてる.

編集 削除
堀江伸一  2011-06-04 16:10:06  No: 72705  IP: 192.*.*.*

STL標準講座について調べてました。
>特にイテレータについての解説が非常に貧弱なのが致命的な欠点です。本書だけで、STLのイテレータを完全に理解するのは困難でしょう。
とアマゾンのレビューにあったので
より専門そうな  Effective STL—STLを効果的に使いこなす50の鉄則
を購入することにしました。


stlのコンテナを複雑に組み合わせた時の追加削除メモリ解放での注意点、その時のiteratorの挙動について学べたらと思います。

queue<map<map<class1,vector<int> >,int>,class2>> q;のようなだんだん複雑な組み合わせになる(実務だともっと複雑になる?)コード。

こういうコードでiteratorを回してる途中での追加削除、データの列挙やソート基準の変更、複数のiteratorを回しているコンテナに対する追加削除に関する注意.
コンテナ内部を指すために外部で確保したポインタ配列の取り扱い。
色々な場合の注意点を原理から理解できたらと思います。

ようやく少し複雑なコンテナの組み合わせというものを学習し始めたばかりなので、まだまだ初心者です。
まだ私は数種類のコンテナをちょっと複雑に組み合わせてみようというレベル。

マルチタスク下でのコンテナの安全な運用など全く未学習です。
両方のタスクで同じコンテナに対して得iteratorを動かしている時等どうすれば安全にデータを取り扱えるのか?
コンテナについては学習することだらけという感じです。


JIS X 3014:2003については
http://www.jisc.go.jp/app/pager?id=7429というページで無料で閲覧できるようなので閲覧しようとしたら
X3014_01(PDFファイル:18217KB 別ウィンドウでリンク)
をクリックしてもページが読み込み中で止まったままで閲覧できませんでした。
何か特定バージョンのAdobe Readerかブラウザでないと閲覧できないのでしょうか?
よくわかりませんでした。

17325円は高いので、もっと安い本、もしくは図書館で学習できたらと思います。
近隣の図書館に規格書が置いてあればいいのですが、一度図書館に行ってみます。

編集 削除
tetrapod  2011-06-04 19:53:27  No: 72706  IP: 192.*.*.*

大丈夫。
実務でそんな無意味に複雑なコンテナ使ったりすることは *絶対に* ないから。
「とてつもなく複雑なデータ」なんて扱いきれない。

挿入除去検索が入り乱れて行われるような状況だったらデータベース使う。

実務を知らないが故の自分勝手な杞憂に踊らされているようだね。

編集 削除
επιστημη  URL  2011-06-05 13:04:36  No: 72707  IP: 192.*.*.*

誤解があるといけないのでヒトコト。

> 例えばvectorのiteratorを回している時に要素を追加してはいけない。
> とかあるようですが、他に注意する点はあるでしょうか。
> 回している時に要素をvectorに追加するとvectorの要素が壊れることがあるそうですが...

壊れるのはvectorの要素じゃなくiteratorの方。
iteratorが狂ってアサッテの(ありもしない)要素を指すことがあります。
# 土地計画に伴う地番変更により郵便が宛先不明で届かなくなるよなもんね。

編集 削除
tetrapod  2011-06-05 19:51:36  No: 72708  IP: 192.*.*.*

っていうか vector も iterator も「壊れ」「狂い」はしないよね。
iterator が指す先に vector (の要素) がいなくなる (移動する) だけ。

void* p=malloc(1000); // vector だと思いなはれ
void* q=p; // この q が iterator だと思いなはれ
p=realloc(p, 10000); // vector::resize だと思いなはれ
// ここで q が指す先には vector は既にない (かもしれない)
// 上記 realloc は良くない使い方なのでまねしないこと。

編集 削除
堀江伸一  2011-06-06 10:15:03  No: 72709  IP: 192.*.*.*

tetrapodさんへ。
やはり技術屋故のプロフェッショナルなんて部分もあるのかななんて想像したりはします。
指標が分かるのありがたいです。

>επιστημη
イメージつかめてきました。
メソッドでデータが壊れることはないということですね。

gccではiteratorを回してる時、it.追加削除のメソッド等を適用するとルール違反でエラー、BCCではこれがコンパイルが通り一応動く。
など色々あるみたいで、すこしその辺がごっちゃです。
BCCでは引越しに対する対処がきちんとしているのか?
色々疑問がわきます。

プログラムの世界は右を見ても左を見ても分からない事だらけ。
DirectXの使い方とかWin32APIによるGUIアプリ制作時の設計図の引き方とか、わからないことだらけ。
もっと色々学習して早く中級者と名乗れるようになりたいです。

編集 削除
επιστημη  URL  2011-06-06 19:35:27  No: 72710  IP: 192.*.*.*

> gccではiteratorを回してる時、it.追加削除のメソッド等を適用するとルール違反でエラー、BCCではこれがコンパイルが通り一応動く。
> など色々あるみたいで、すこしその辺がごっちゃです。

やっちゃいけないことやったときの挙動の違いなんか気にするだけムダです。

> プログラムの世界は右を見ても左を見ても分からない事だらけ。

誰だってそうよ。調べ方知ってれば無問題。

編集 削除