例えばサンプルAのようなforループがあります。
forループの最中temp1.Lengthが不変であることは文脈から明らかです。
コンパイラの最適化オプションが賢ければ、temp1.Lengthの計算を一回で済ませ、
以降はその値を基にループ終了の判定をしてくれるはずです。
コンパイラの最適化オプションが賢くなければ、毎回temp1.Lengthを計算します。
実際はどうなのでしょうか?
私は無駄な計算を避けるために、わざわざサンプルBのような記述をしています。
コンパイラが十分賢いことが分かれば、わざわざサンプルBのような書き方をする必要が無くなります。
// サンプルA
int[] temp1 = new int[1000];
// Lengthプロパティは毎回呼び出されるのか?
for(int i = 0;i < temp1.Length;i++)
{
temp1[i] = i;
}
// サンプルB
int[] temp1 = new int[1000];
//
int num = temp1.Length;
for(int i = 0;i < num;i++)
{
temp1[i] = i;
}
注意
Lengthプロパティによるオーバーヘッドは実際は微々たるものです。
上記サンプルは説明用に作成したもので実用的ではありません。
Lengthよりはるかに重たいプロパティの場合、毎回計算されることによる
オーバーヘッドが問題になります。
ひろし wrote:
> 私は無駄な計算を避けるために、わざわざサンプルBのような記述をしています。
それが正解かと。
ひろし wrote:
> Lengthプロパティによるオーバーヘッドは実際は微々たるものです。
> 上記サンプルは説明用に作成したもので実用的ではありません。
> Lengthよりはるかに重たいプロパティの場合、毎回計算されることによる
> オーバーヘッドが問題になります。
―― ということをご理解しているのであれば、その「重たいプロパティ」
なるものがループ内の処理に影響される可能性についてもお分かり
いただけるかと思います。
コンパイラとしては額面どおりにプロパティを取得するしかなく、最初に
取得した値をキャッシュすることはできないはずです。
そのような最適化が可能かどうかはプログラマの責任において判断し、
そのロジックを明示的にコードで表現しなければなりません。
ちなみに、MSILには配列の長さを取得する専用命令ldlenがあるので、
他の一般的なプロパティとは少々条件が異なります。しかし、専用命令
があるとはいえ、配列はSystem.Arrayクラスのインスタンスなので、
プロパティがオブジェクトで管理されている以上、その値をキャッシュ
することはないと思います。
こちらで適当なプログラムを逆アセンブルして調べたかぎりでは、ldlen
命令も毎回実行されていました。
--
植田システム設計事務所
Ueta System Design Studio
http://www.usdesign.jp/
植田真一
mailto:ue...@usdesign.jp
余談ですが、
最近のコンパイラはおとなしいので少し物足りないです。
ミニコンや汎用機で科学技術計算用コンパイラを使って
ガンガン最適化していた時代がちょっとなつかしいです。
"UETA, Shin-ichi" からの元のメッセージ: