The Delphi Bug List

Entry No.
117
コンパイラ
ユニットの initialization セクションが実行される前に、そのユニット内の関数や手続きを呼び出すことが出来る
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 4.03 5.0 5.01 6.0 6.01 6.02 Kylix 1.0
Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Gotcha Unknown
解説
Reported by Scott Stephenson; checked by Arjen Broeze
initialization セクション内に呼び出し元がある場合、別のユニットの関数や手続きを、その別のユニットの initialization セクションが実行される前に呼び出すことが出来てしまいます。これは特徴であってバグではありませんが、ある種のとても面倒な問題を起こす場合があります。

再現方法:
これは非常にねじれた uses 節を持つ複雑なプロジェクトにおいて発生する傾向があります。私たちはこれを Pannon-Rex オブジェクトユニットで発見しました。そのユニットでは、initialization セクションでストリーム登録リストのルートノードに nil をセットしていました。不運なことにその initialization は、別のユニットの initialization 節で別のストリーム可能なオブジェクトが登録された後に実行されていました。そのため、ルートノードが nil にセットされたとき、すでに登録されていたオブジェクトが見失われていました。

これはバグだと思いますか?
これはバグではなく、実際は(悪い)言語設計の特徴です。全員が知っておくべき基本的なことは、ユニット内のコードが呼ばれる前にそのユニットの initialization 節が実行されることを当てには出来ないということです。個人的な控えめの意見としては、"Initialization" は "Not_really_initialization" とでも名前を変更するべきだと思います……
解決策 / 回避方法
とても完璧な対処法:
initialization を一切使用しないか、少なくとも initialization セクション内のコードからそのユニット外の呼び出しを避けてください。
Andreas Prucha 追記:
この問題は、ユニットが互いに uses し合っていない場合には発生しません。その場合 initialization セクションを使用し続けることが出来ますし、ユニット外のスコープの呼び出しも可能です。uses し合っている場合でも、プロジェクトファイルの USES 節の順序を呼び出し側が先になるように変更することで、この問題を避けられる場合があります。
Latest update of this entry: 1998-06-11
本家 The Delphi Bug List のエントリーはこちら
The Delphi Bug List 日本語訳 へ