InstanceClass.NewInstance+Instance.CreateとInstanceClass.Createの違い。
方法1:
Instance := TComponent(InstanceClass.NewInstance);
Instance.Create(Self);
方法2:
Instance := InstanceClass.Create(Self);
どちらが良いですか?
InstanceClass.Create
適切な場合は常に使用します – そして常にそうです.
理由はたくさんあります。非常に良いのは、1 行のバージョンの方が簡潔であることです。もう 1 つの理由は、シングル ライン バージョンが標準的で一般的に使用されるアプローチであることです。
さらに別の理由は、メソッド 1 が正しく管理しないコンストラクターでの例外の処理です。例外が発生した場合、新しいインスタンスは破棄されますが、インスタンス変数はまだ割り当てられています。これは方法 2 との重要な違いであり、Delphi のすべてのライフタイム管理規則に反します。
あなたは言及しTApplication.CreateForm
ます。それを見てみましょう:
Instance := TComponent(InstanceClass.NewInstance);
TComponent(Reference) := Instance;
try
Instance.Create(Self);
except
TComponent(Reference) := nil;
raise;
end;
Reference
これは、パラメーターとして渡すフォーム変数であることを忘れないでvar
ください。これに関するポイントは、このコードがコンストラクターを呼び出す前にそのフォーム変数を割り当てることです。通常、その割り当ては、コンストラクターの完了後にのみ行われます。
おそらくこれは、フォーム変数 (多くの場合、グローバル変数) を参照するコードが、そのフォームのコンストラクター内から呼び出された場合でも機能できるようにするためです。これは非常に特殊なケースであり、ルールというよりは圧倒的に例外です。この特殊なケースによって、主流のコーディング スタイルが動かされないようにしてください。
(IMHOの他の人は完全ではないので、この回答を追加しました)
方法 2 が正しい方法です。
メソッド 1 は、コンストラクター呼び出しに隠しパラメーターがあり、適切な初期化に失敗する可能性があるため、呼び出されない場合: 実際、NewInstance
クラスごとの疑似仮想メソッドです!
実際、コンストラクター呼び出しには隠しboolean
パラメーターがあります (register EDX
、EAX
=class であるため)。公式ドキュメントで述べられているように:
Boolean
コンストラクターとデストラクターは、コンストラクターまたはデストラクター呼び出しのコンテキストを示すために追加のフラグ パラメーターが渡されることを除いて、他のメソッドと同じ呼び出し規則を使用します。コンストラクター呼び出しの flag パラメーターの値は
False
、コンストラクターがインスタンス オブジェクトを介して呼び出されたか、継承されたキーワードを使用して呼び出されたことを示します。この場合、コンストラクターは通常のメソッドのように動作します。コンストラクター呼び出しの flag パラメーターの値はTrue
、コンストラクターがクラス参照を介して呼び出されたことを示します。この場合、コンストラクターはclass
指定された のインスタンスを作成Self
し、 で新しく作成されたオブジェクトへの参照を返しますEAX
。
特に、そのように呼び出された場合、クラスは_ClassCreate
関数を呼び出しません。NewInstance
クラスがデフォルト関数で作成されない場合、クラスの初期化に失敗する可能性があります。実際、この関数はクラス VMT に挿入されています。まれに、オーバーロードされる場合があります (たとえば、別のメモリ割り当てパターンを提供するために - ガベージ コレクターまたは速度最適化アロケーターである可能性があります)。したがってInstanceClass.NewInstance
、いくつかの境界ケースでは、直接呼び出すとバグが発生する可能性があります。
function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
asm
...
TEST DL,DL
JL @@noAlloc
CALL dword ptr [EAX].vmtNewInstance
@@noAlloc:
...
したがって、InstanceClass.NewInstance
直接呼び出すことは、2 つのオーバーライドされたものをキャンセルしたい場合にのみ、意図的に行う必要がvmtNewInstance / vmtFreeInstance
あります (この場合、 も呼び出す必要はありませんが.Free / .Destroy
、メモリを使用しない関数を所有しています)。したがって、内部で低レベルの微調整を行う必要がない限り、 Embarcadero (およびFreePascalチーム) によって設計および文書化されているように、 をNewInstance
呼び出すことはありません。constructor
方法 1 を使用してオブジェクトを作成しないでください。99.9% の確率で動作する可能性がありますが、場合によっては失敗するか、将来のコンパイラ/RTL 拡張 (ガベージ コレクターなど) で失敗する可能性があります。VCL が を使用することがあっても、NewInstance
使用しないでください。むしろ、このメソッドを保護することをお勧めします。
継承されたコンストラクターを呼び出すには、コンストラクター内で手続き型の形式を使用する必要がありますが、クラス インスタンスを作成するための標準的な方法であるため、2 番目の方が優れています。