The Delphi Bug List

Entry No.
629
コンパイラ - ヒントと警告
string を返す関数が Result を初期化していない場合でもコンパイラは警告を出さない
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
N/A Exists Exists Exists Exists Exists Exists Exists Exists Exists Exists Exists Exists Exists Exists
解説
Reported by Jordan Russell
string を返す関数が Result を初期化していない場合でもコンパイラは警告を出しません。この動作は、Delphi が string 型のローカル変数と同じように string 型の Result 変数もクリアすると思い込ませてしまいますが、実際にはそうではありません。

以下のコードを良く見てください:
function Test(AssignResult: Boolean): string;
begin
  if AssignResult then
    Result := 'a';
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
begin
  S := Test(True);
  S := Test(False);
  Caption := S;
end;

Caption に代入されるときの S の値は何でしょうか?おもしろいことに、'a' になります。関数 Test の1回目の呼び出しが Result に 'a' をセットします。関数 Test の2回目の呼び出しは Result に何も代入しません。それにもかかわらず 'a' を返す理由は、Delphi が2回の呼び出しの両方で内部的に同じ string 型変数をクリアせずに渡しているということです。

わたしは、ここで警告が出ないことをコンパイラのバグだと考えます。なぜなら Delphi は、Integer を返す同じような関数では警告を出すからです。例:
function Test(AssignResult: Boolean): Integer;
begin
  if AssignResult then
    Result := 1;
end;
解決策 / 回避方法
空文字列を返したい場合には、必ず Result を '' で初期化してください。Result に何も代入しない場合、空文字列を返すことは保証されません。

上のサンプルは次のように変更するべきです:
function Test(AssignResult: Boolean): string;
begin
  if AssignResult then
    Result := 'a'
  else
    Result := '';
end;
ユーザーからのコメント
Khash Sajadi
03 Mar 2004  11:52 AM GM
この問題は variant を返す関数でも発生します。(Delphi 5 SP1 Enterprise でテストしました)
Khash Sajadi
03 Mar 2004  03:59 PM GMT
この現象についてしばらく考えた後、(任意の型の)strings や、集合、レコード、配列(動的でも静的でも)のような、全ての非固定長の型でこの問題が発生すると確信しました。Borland はプロジェクトのサイズが大きくなるに従ってこの問題が致命的なものになると考えるべきだと思います。
Latest update of this entry: 2002-02-28
本家 The Delphi Bug List のエントリーはこちら
The Delphi Bug List 日本語訳 へ