オブジェクト - みる会図書館


検索対象: ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法
29件見つかりました。

1. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 13 回 関数の返り値はどうあるべきか できる。この数値は、 CL 日のデバッグサービスで生成される正の整数だ。 コビー ( 値の偏集 ( 印 ウォッチ式の追カ動 オブジト ID の作成 ( 瓰 すべて選択 ( 合 ) th [ 三 ] 16 進数で表〒 ( 0 「ⅱ , Texl 、、 / ソースのスレッドを表示する 発 " } ロ 002 ? = ローかト 名国国国 + . ヨらロ e ロ引 オブジェクトに対して、このオブジェクト旧を付与するには、ウォッチウインドウで オブジェクト ID を付与したい変数名のところでマウスの右クリックをして、「オブジェク ND の作成」を選ぶ。こうすると「 1 # 」のように # が後ろについた番号が変数の値を表 示しているところに追加表示される。これがオブジェクト旧だ。 そして、ブレークの時の条件としてこのオブジェクト ID を用いることができる。たと えば、 # 1 のオブジェクトの時だけブレークさせたいならば、「 this = = 1 # 」とブレーク ポイントの条件に書けは良い。 13 267

2. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

ひなた先生が教える くなるテクニック これは、 VisualStudio のメニューから「デバッグ」→「ブレークポイントの作成」 「関数でブレーク」を選択する。 アドレスが OxOO 1 2 幵 4c であることがわかっているなら、次のように指定する。 いま、 Hoge ロ ass の Add という関数でブレークしたいとして、そのオブジェクトの プログラムが関数の次の場所にしたとき、実行を中断します。 プレーり木イントの作成 関数 ( E ) : 行 ( 文字 ( 砂 。ロ ( ( HogeC 唇 s ) ロ x 1 2ff4c ト > Addl オブジェクトのアドレスは、デバッグ実行させて、適当なところでブレークして、ウ ォッチウインドウでその値を確認すると良いだろう。 単に、 HogeClass : : Add でブレークさせたいだけならば、「 HogeClass::Add 」とこ こに記述すれば良い。しかし、その場合は、この機能を使わずに該当行に〔〔〕でブレー クポイントを設定するほうが手つ取り早いだろう。 また、特定のインスタンスの関数呼び出しでブレークする場合も、ブレークさせたい 関数の先頭にブレークポイントを設定して、そのブレークポイントの条件として 「 this==OxOO 1 2 幵 4c 」のように設定するほうが手つ取り早いかも知れない。 プレーり木イントの条件 ブレークポイントの位置にしたときに、式が評価され、式が true か変わった場合にのみブレークポイ ントをヒットします。 曰条件 ( 胎に = : Ox0012ff4c 〇 true の場合① O 変更された場合 ( ところで、以上の機能は C # では使えない。なぜなら、 managed code ではオブジェ クトは、 GC (Garbage Collection) によって別のアドレスへ移動することがあり、オ ブジェクトが特定のアドレスに留まったままであるという保証がないため、特定のメモ リの値が変更されたらブレークと言った手法が通用しないからである。 その代わり、オブジェクトには、オブジェクト ID という unique な旧を付与することが 266

3. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 7 回 proxy object によるバグの再現 第 0 爾一日 0 「まあ、その・・・なんだ。男には忘れなくてはならないときがあるんだ」 なんだよそれ、とケンイチは思った。 「ところで、今日は、あるプログラムのデバッグをしてほしい。ラッキーなことに 醤油はないけどソースはある。がはははははは」 咼らかに笑う早井。 乾いた笑いがこみ上げてくるケンイチ。 「だからして、これは、いつにもまして簡単だぞ。これが終わったら帰ってョロシ 「やった一 ! 」 そうは言っても、いままでに何度も早井に騙されているケンイチにとって、手放しで喜 んでいいのかどうか判断っきかねていたが。 ヘビー級オプジェクトの巻 ケンイチがデバッグを頼まれたプログラムは、巨大なプログラムだった。クラス定義だ けで何千行もあった。ケンイチはめまいがした。 ケンイチは、バグ発現のために不要となる部分をソースからコメントアウトしていき、 結局、バグの発現のためには、猫 , 犬と蛙の 3 つのオブジェクトが必要だというところま で突き止めた。 あとは簡単にデバッグができるかと思いきや、新たな問題がケンイチを待ちうけていた。 猫オブジェクトは、 web 上にデータを取得しに行くのだが、そのデータは 13 : OO ~ 13 : 05 , 14 : OO ~ 14 : 05 , 15 : OO ~ 15 : 05 のように 1 時間に 5 分間しか取得できないのだ。これにはケン イチも参った。 135

4. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 テパッグが 電 1 ーくなるテクニック 「苦ではないかもしれないけれど、 SomeFunc 日 esu は . Ok なんて書いてあると、ず いぶんと読みにくいと思うんだけども。本当にそんなのが流行ってるの ? 」 「いえ。最近のトレンドで言えば・・・そうですね、たとえば、 . NET Framework では、 工ラーはたいてい例外で返すのが標準的であるため、返り値をエラー要因を表すた めに使うことはあまりありません」 . ~ 「ふーん。そうなんだ ? じゃあ、今まではどうして例外を用いなかったの ? 」 「 C + + の場合、例外が発生したあと、 stack の「 ewinding ( 巻き戻し ) が発生します」 「ええと、こういうことか ( リスト 12 ) ? 」 V リスト 1 2 C + + の stack の rewind void g() ひなた先生が教え 日臼 t ry { f ( ) } c a t c h ( . vo i d f ( ) Hoge hoge; throw null; 「この場合、関数 f で例外が発生すると、関数 f 内の stack 上に配置されているオブ ジェクト ( ここでは hoge ) のデストラクタを呼び出して、関数 g の catch で例外が 捕捉されると」 「はい。例外が catch されるまで stack 上のオブジェクトを次々に解体していく必要があ ります。そのことを stack の rewinding と呼びました」 「 C # だと、そういうコストはないのか ? 」 「はい。 GC ()a 「 bage Collector) がどこからも参照されなくなったオブジェク トを自動的に回収してくれますから、例外発生時に stack の rewinding を行う必要 はありません。ですので、 C + + で例外が発生した場合よりは、はるかに小さいオー バーヘッドで済みます。このため、 C + + よりは気軽に例外を使えます」 252

5. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 ひなた先生が教えるテみーッグカぐ ! = ーー - 」くなるテクニック 。「これでは、実質的に 1 時間に 5 分しかデバッグ作業が行えないじゃないか」 ケンイチは、また早井に騙されたのだと悟った。 , 。「今、デバッグを困難にしているのは、 Web 上のデータを取得できる時間帯が限ら れていることだ。猫オブジェクトが 1 時間に 5 分しか正常に動作しないからいけな いのだ。では、 1 時間中ずっと動作する偽の猫オブジェクトを作ってはどうだろう か ? ( 図 9 ) 」 v 図 9 オブジェクト指向 ( のイメージ ) P 「 OXY 0 「 e 引 乞「正常に Web 上のデータが取得できるときは、取得して、そうでないときは嘘の値 を返す。いや、待てよ。嘘の値を返そうにも、まるつきりでたらめな値だとプログ Nyanko クラス ( これが図 9 の p 「 oxy に相当する ) を書いた。 もとの Nyanko クラスを Nyanko ー Re 引と名前を変更した。そのあと、 考えていても仕方ないと思ったのか、ケンイチはコードを書き出した。ケンイチはまず、 ラム自体が機能しないぞ・・・」 リスト 1 のような Nyanko(){ pub い c : class Nyanko ( virtual int getData(int n) struct NyankoInterfaceC マリスト 1 Nyanko Proxy 136 nyanko = new Nyanko—Real();

6. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

の , 2 らも危う : !< なるテクニック テ / ーッグが 「突き刺してある木が『バグが発現する』という条件なわけですね。その条件を保ち ながら、砂山を少しずつ削っていく。結局、その突き刺している木を支えている部分 は何なのか。それを特定するのがデバッグ作業なのだ、と」 「ケンイチ君って察しがいいのね ! 」 「でヘへへへ。それほどでもありますけど」 ケンイチの顔がとろけてきた。 「ケ・・・ケンイチ君」 ひなた先生がとても困った顔になった。そのときお昼休みを知らせるチャイムが鳴った。 楽しい時間は、いつだってすぐに過ぎ去る。 ひなた先生が教える 00 削ろうにも削れないの巻 ケンイチはお昼を会社近くの公園で過ごすのが最近の日課となっている。ケンイチはべ ンチに腰掛け、先ほどのプログラム変換について考えていた。 「今、『バグが発現する』という条件を保ったままプログラムを縮退させていくこと を考えよう。『バグが発現する』までに呼び出していない関数は削れるし、バグが 再現できる限りはどんどん削っていって良い。バグを再現させるための機能体さえ 残っていればそれでいいのだ」 ケンイチは、お弁当の卵焼きを頬張るときに、あることに気付いた。 「あっ。それはそれほど簡単ではないのではないのか ! ? オブジェクト指向プログラミングにおいては、それぞれのオブジェクトが協調して 処理が進んでいく。今、猫 , 犬 , 蛙 , 兎のオブジェクトがあるとしよう」 ケンイチは、ひなた先生が徹夜して作った動物マグネットのことを思い浮かべた ( 図 8 ) 。 132

7. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 ひなた先生か教えるテ / ーッグが 1 = ー - ー丿くなるテクニック までが使用領域であり、 a [ inde 刈自体は未使用領域であることがわかる。つまり図 5 が正 いや、 GetEnumerator の実装を読まなくとも初期状態で index = 0 であり、初期状態で はすべての要素が未使用なのだから図 6 のモデルではおかしい。やはり図 5 でなければなら ◆◆◆ ケンイチは index という変数の意味は確定できたものの、この変数に関してはドキュメ ンテーションがないのが不親切だと感じた。せめて「 a Ⅳ [ O ] ~ a Ⅳ [ index -1 ] までが使用中の オブジェクト。 ary[index]æary[Capacity-1] までが未使用のオブジェクト」のような説明 が欲しいところだ ( →第 9 回 ) 。 ケンイチは次に、 Enqueue メソッドを見た。よく見ると Enqueue が返し値を持っており 「削除される値を返す」と書いてある。標準の Queu T > の Enqueue には返し値などない はずだ。 FixedSizeQueue はこの queue を cache 目的で使うので、 Enqueue したときに cache から purge されるオブジェクトを返しているのだろうな、ということはわかった。 場合によっては、 Enqueue の返し値は void にしておき、 pu 「 ge するときに IDisposable Obj = Old as IDisposable; i f ( ob j ! = nu は ) ob j . D i spose ( ) のように Enqueue メソッド内で Dispose したほうが良いのでは ? と思ったが、 T クラスが どういう性質のものを想定してあるのかわからないのでそれは今は考えないことにした。 Enqueue メソッドがやっていることは、 index が Capacity に達していれば配列の要素を 1 つ隣にスライドしたのちに引数で渡された要素を a Ⅳ [ index ] に詰め込むようだった。「配 列の要素を 1 つ隣にスライドする」というのは良く考えてみれば Dequeue そのものだし、 実際 Dequeue のソースコードがコピべしてある。 ケンイチは目まいを覚えた。また、関数を抜けるための経路 (return) が 2 つ存在する のも気持ち悪い。ケンイチは頭の中でさっとリスト 2 のように書き換えてみた。 300

8. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 15 回バグを憎んで人を憎まず のようにテフォルトサイズとして const で宣言されていたとしても依然として bu 幵 e 「を固定 長にするメリットがどこにもない。 queue を高速化するために buffe 「を配列で確保すると しても、 C + + の std::vector のように不足するごとに 2 の N 乗のサイズの bu 升 er を再確保して いけば良いのではないのか ? つまり、この 32 という固定長でバッフアを確保する設計自 体が胡散臭いと言わねばなるまい。 しかし、この部分は単に「手抜き」なのかも知れない。まずは動くコードを書いて、そ のあと拡張性や汎用性が問われるならば必要に応じて書き足していくというプログラミン グスタイルなのかも知れない。ならば、この 32 には目を瞑るべきか ? ケンイチは悩んだ。 あっ。待てよ。単に動くコードを書くだけならば、 FixedSizeQueue の存在自体が不要 なはずだ。「まずは動くコードを書いて」のつもりならば標準コンテナの Queue く T > で十分 だからだ。名前を FixedSizeQueue にしているのもおかしい。 Queue の高速版のつもりな ら QuickQueue や FastQueue のような名前で良さそうなものだ。 「 FixedSizeQueue にあって、 Queue く T> にはない」ような機能がどこかにあるのか ? い や、ないだろう。 Enqueue/Dequeue/Remove のどのメソッドも Queue<T> に備わって いるメソッドだ。もし動くコードをまずは書いて、あとで高速版の自前の Queue に置き換 : 川 えるつもりでいるなら、ここは単に pubLic class Qui ckQueue く T> : Queue く T> { } とだけ書くべきところだろう。そう書かなかったのは、 の高速版以上の意味を持たせたかったからに違いない。 この queue クラスには Queue<T> ケンイチは、 Visual studio でこの FixedSizeQueue クラスの「すべての参照の検索」を 行い、 FixedSizeQueue が使用されている個所を確認した。 やはりそうだ。 cache 目的で、この queue が使われている。つまり、このソースコード の書き手はこの queue クラスで cache 機構を実現したかったようだ。 cache 機構を実現す るのに queue を使うことはある。それはケンイチにも理解できる。 cache 機構においては、ひんばんにアクセスされるオブジェクトを cache 内に保持して おきたい。逆に、あまりアクセスされないオブジェクトは cache から purge ( 追い出す ) し たい。そのためには、一番新しい時刻にアクセスされたオブジェクトを queue の先頭に移 297

9. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

0 ノ多。匕りの - ー : ー , くなるテクニック テパッグが ひなた先生が教える 「ええ。 shallow copy とも言えますが・・・どちらかと言うと、 C + + の場合は bitwise c 叩 y ( ビット単位のコピー ) ですね」 get は read と違うの巻 「ケンイチ君のおかげでなんとなく記憶が蘇ってきたよ」 「あの、 C # のプロバティの構文なんだけど、 get と set ってどこか直観に反するんだ 「どうしてですか ? 」 「それは良かったですね ! 」 0 使って、値を w 「 ite するときに set を使うような印象を受ける」 「 get は取得する、 set は設定するって感じがするから、値を「 ead するときに get を 臼 「あー 言われてみればそうですね」 を 「だけど、実際は、「 ead するときも w 「 ite するときも get だ。オブジェクトを get し て、そいつのメソッドで「 ead なり w 「 ite をしなくてはならない。オブジェクトを設 定しなおすときだけ set だ。このへん、つい錯覚してしまう」 「その経験は私もあります・・・。その錯覚の原因は、 C の関数で引数にポインタやら参照や ら渡しているのに違和感があるのと同じ原因かもしれませんね」 「そもそもなぜ、 C # のプロバティは引数を取れないんだ ? バラメータを取らせても らえないと、どうにも不便だ」 「さあ・・・」 「はい。それは区別せずに済むならそれに越したことはないと思います」 う気がしてきた」 「あとさ、参照と値型とを区別しないといけない言語は良くないんじゃないかとい 286

10. ひなた先生が教えるデバッグが256倍速くなるテクニック : 実践的ソフトウェアデバッギングの手法

第 14 回 ポインタと参照との関係 たとえば、 C # で、 DateTime 型は参照透明だが、 DateTime. Now は現在の時刻を返 すので参照透明とは言えない。 よって、次のようなプログラムを書いた場合、 dl と d2 の値が同しとは限らない。 DateTime. Now; DateTime dl DateTime d2 DateTime. Now; このプログラムならば見ただけでおかしいことに気付くだろうが、次のように離れて いるとおかしいことには気づきにくい。 Database . UpdateTime = DateTime. Now; Database . ReferenceTime DateTime. Now; そのため参照透明ではないオプジェクトはなるべく参照透明なオプジェクトにコピー して扱う習慣をつけたほうが良い。 DateTime now = DateTime.Now; Database. UpdateTime = now; Database.ReferenceTime = now; また、 Java や C # のように参照でオプジェクトを扱うのが基本となる言語では、その オプジェクトが参照透明なのか参照透明ではないのかを強く意識しながらプログラムを したほうがバグを減らせるだろう。 289