Delphi変数はデフォルトで値で初期化されますか?


103

私はDelphiを初めて使用し、デフォルトで初期化されているオブジェクト変数とスタック変数を確認するためにいくつかのテストを実行してきました。

TInstanceVariables = class
  fBoolean: boolean; // always starts off as false
  fInteger: integer; // always starts off as zero
  fObject: TObject; // always starts off as nil
end;

これは私が他の言語で慣れている動作ですが、Delphiでそれを信頼しても安全かどうか疑問に思っていますか?たとえば、コンパイラの設定に依存しているのか、それともマシンによって動作が異なるのかと思います。オブジェクトのデフォルトの初期化値に依存するのは普通ですか、それともコンストラクタですべてのインスタンス変数を明示的に設定していますか?

スタック(プロシージャレベル)変数については、私のテストでは、単一化されたブール値がtrue、単一化された整数が2129993264、未初期化オブジェクトが無効なポインター(つまりnilではない)であることを示しています。それらにアクセスする前に、常にプロシージャレベルの変数を設定するのが標準であると思いますか?


3
2つの注意:1.レコードは初期化されません。2.参照カウントされた変数は常に初期化されます。!だが!文字列を返す関数では、 'Result'は期待どおりに空の文字列に初期化されません。これは、「結果」がローカル変数ではないためです。したがって、常に次のようにしてください。Result:= '';
InTheNameOfScience 2017年


これはあなたの質問に答えますか?Delphiでどの変数が初期化されますか?
InTheNameOfScience

回答:


105

はい、これは文書化された動作です:

  • オブジェクトフィールドは常に0、0.0、 ''、False、nil、または該当するものに初期化されます。

  • グローバル変数も常に0などに初期化されます。

  • ローカル参照カウント*変数は常にnilまたは ''に初期化されます。

  • ローカルの非参照カウント*変数は初期化されていないため、使用する前に値を割り当てる必要があります。

私はそれを覚えている バリー・ケリーがどこかで「参照カウント」の定義を書いたいますが、それを見つけることができなくなったので、これは当面は必要です。

参照カウント==自分自身が参照カウントされるか、直接または間接的に次のように参照カウントされるフィールド(レコードの場合)または要素(配列の場合)を含む:string, variant, interface または動的配列または静的配列、このようなタイプを含有します。

ノート:

  • record それ自体は参照カウントになるのに十分ではありません
  • 私はこれをジェネリックでまだ試していません

2
Giacomoが以下のコメントで指摘したように、これはすべてms-help://borland.bds4/bds4ref/html/Variables.htmにあるDelphiヘルプファイルで説明されています。Delphi 2009では、「変数」のヘルプを検索して同じ情報を見つけました(おかしなことに、たくさんの検索を試してみましたが、そうするつもりはありませんでした)。
MB。

8
ローカル変数は、文字列、インターフェース、動的配列、バリアントなどのマネージ型の場合、初期化されます($ 0)
Francesca

5
ただし、例外があります。コンストラクターをオーバーライドし、継承されたコンストラクターを呼び出さない場合、一部のフィールドが初期化されないままになる可能性があります。(特に古いDelphiバージョンの場合。)TObject.Createはすべてのデータをゼロにする責任があるため、1つを呼び出さないで不明なデータが発生する可能性があります。
Wim ten Brink 10

18
@WimtenBrink私はあなたが間違っていると思います。初期化はTObject.Createvoidメソッドである内では行われませんが、class function TObject.InitInstance(Instance: Pointer): TObject;古いDelphiバージョンであっても、コンストラクタ呼び出しの前に必ず呼び出されます。あなたのコメントは私見で間違っていて混乱しています。
Arnaud Bouchez

7
文字列を返す関数では、 'Result'は期待どおりに空の文字列に初期化されないことを忘れないでください。これは、「結果」がローカル変数ではないためです。
InTheNameOfScience 2015

27

明示的な初期化子を持たないグローバル変数は、実行可能ファイルのBSSセクションに割り当てられます。実際には、EXE内のスペースを占有しません。BSSセクションは、OSが割り当ててゼロにクリアする特別なセクションです。他のオペレーティングシステムでは、同様のメカニズムがあります。

ゼロで初期化されるグローバル変数に依存できます。


21

クラスフィールドはデフォルトでゼロです。これはドキュメント化されているため、信頼できます。ローカルスタック変数は、文字列またはインターフェイスでない限り未定義です。これらはゼロに設定されます。


ありがとう。「ゼロ」は私を少し混乱させます-それは文字列が ''であることを意味し、インターフェイスはnilですか?
MB。

4
はい、まさにその通りです。nil = 0(アセンブラレベル)および '' = nil(Delphi規則)。
gabr 2008

1
「文字列またはインターフェースを除いて」は、現実を完全に説明するものではありません。たとえば、動的配列も初期化されます。より一般的には、管理された(参照カウントされる)型の変数は、ローカルであっても初期化されるという規則です。
Andreas Rejbrand


7

これは、第2章のレイリシュナーデルファイからの引用です。

「Delphiが最初にオブジェクトを作成するとき、すべてのフィールドは空で始まります。つまり、ポインタはnilに初期化され、文字列と動的配列は空であり、数値はゼロ、ブールフィールドはFalse、バリアントはUnassignedに設定されています。 (詳細については、第5章のNewInstanceおよびInitInstanceを参照してください。) "

スコープ内のローカル変数を初期化する必要があるのは本当です...上記の「グローバル変数は初期化される」というコメントは、参照が提供されるまでは疑わしいものとして扱います-信じられません。

編集... Barry Kellyは、それらがゼロで初期化されることを信頼できると言います。彼はDelphiコンパイラチームにいるので、私はそれが正しいと信じています:)ありがとう、Barry。


1
delphi 2006のヘルプでは、ms-help://borland.bds4/bds4ref/html/Variables.htm「グローバル変数を明示的に初期化しない場合、コンパイラはそれを0に初期化します。オブジェクトインスタンスデータ(フィールド)も0に初期化されます。 "
Giacomo Degli Esposti

「信じられない」という理由で反対票を投じました。これはプログラミングではなく、宗教です。そしてジャコモは真実を示した。
InTheNameOfScience

6

グローバル変数とオブジェクトインスタンスデータ(フィールド)は常にゼロに初期化されます。Win32 Delphiでは、プロシージャとメソッドのローカル変数は初期化されません。それらの内容は、コードで値を割り当てるまで未定義です。


5

言語がデフォルトの初期化を提供する場合でも、それらに依存する必要があるとは思いません。値に初期化すると、言語のデフォルトの初期化について知らない可能性がある他の開発者にとってより明確になり、コンパイラ間の問題を回避できます。


4
もちろんできます。そして、あなたはすべきです。すべてのコンストラクターですべてを0 / '' / false / nilに初期化する必要はありません。一方、グローバル変数の初期化はそれほど愚かではありません-(私はそれらをあまり使用していないため)初期化されているかどうかを一度も覚えることはできません。
gabr 2008

2
Delphiで変数を宣言したのと同じ時点で変数を初期化できる場合(例:var fObject:TObject = nil)値への初期化がおそらく良いアイデアであることに同意する傾向があります。しかし、私には、すべてのオブジェクトフィールドのコンストラクターでそれを行うことは少し多く思えます。
MB。

4

Delphi 2007ヘルプファイルから:

ms-help://borland.bds5/devcommon/variables_xml.html

「グローバル変数を明示的に初期化しない場合、コンパイラーはそれを0に初期化します。」


3

与えられた答えには少し不満があります。Delphiは、グローバルと新しく作成されたオブジェクトのメモリ空間をゼロにします。これは通常、初期化されていることを意味しますが、初期化されていない場合が1つあります。ゼロが正当な値でない場合はどうなりますか?


1
ゼロは常に正当な値であり、列挙型の最初の値です。ord(MyFirstEnumValue)で確認できます。
フランチェスカ

列挙型の最初の値を返します。
skamradt 2008

6
列挙型に明示的に値を割り当てる場合、ゼロは常に有効な値ではありません。その場合、それはまだ0に初期化されており、不正な値があります。しかし、列挙型は通常の整数型の上に描かれた構文上の糖衣なので、これは実際には何も壊しません。コードで処理できることを確認してください。
メイソンウィーラー、

2
@François:次のように列挙型を定義した場合はそうではありません:TOneTwoThree = (One=1, Two=2, Three=3);
fnkr

0

新しく導入された(Delphi 10.3以降)インライン変数により、初期値の制御が容易になりました。

procedure TestInlineVariable;
begin
  var index: Integer := 345;
  ShowMessage(index.ToString);
end;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.