2011-12-31 6 views
3

Delphi XEプログラムで非常に断続的なメモリ破損を検索する際に、クラス内のいくつかのフィールドを初期化するクラスコンストラクタが見つかりました。次にが継承されます。初期化は、コンストラクターが最初に書かれた後、誤って間違った場所に追加された後に追加されたものだと思います。私は今、継承されたものを最初に呼び出すように修正しました。このクラスのメソッドでは、メモリ破損の例外がほとんど常に発生します。継承を間違って呼び出すと、どのような被害がありますか?

質問:この間違いが断続的なメモリ破損を引き起こした可能性はありますか?コードをトレースすると、そうは思われませんが、私はこの修正が断続的な問題を解決するものであることを本当に望みます。それが問題を解決した後しばらくは起こらないということは、それがなくなったことを証明するものではありません。

いくつかのコード:あなたは(それがターボPascalや「古い」オブジェクト・モデルで働いていませんが、それはデルファイ「新しい」オブジェクトに許可され、継承されたコンストラクタを呼び出す前に、オブジェクトのフィールドを初期化することができますDelphiでは

Tmyclass = class 
    ctype : integer; 
    ts : tstringlist; 
    th : thandle; 
public 
    Constructor Create; 
    Destructor Destroy; override; 
    ... 
end; 

Constructor Tmyclass.Create; 
begin 
    ctype := 3; 
    doinit; 
    inherited; 
end; 
+4

私たちにいくつかのコードを見せてください。あらゆる種類のものが間違っているかもしれないし、そうでないかもしれない。 –

答えて

5

は、オブジェクト作成の一般的な手順である:オブジェクト・インスタンスの

  • メモリ割り当て、
  • すべてのメモリをゼロで埋めます(すべてのフィールド、特に文字列を初期化します)。
  • 最新の子から順に、すべての親を呼び出すように、inheritedを呼び出すことで、コンストラクタとデストラクタの両方にinheritedを記述する必要があります。

inherited親のレベルを指定することもできますし、そうすることができると確信できる場合はnoneを呼び出すこともできます(しかし、SOLIDの原則を破る可能性があります)。実際に

は、constructorが呼び出されたときに、方法に加え隠れパラメータである:

コンストラクタとデストラクタは、追加のブールフラグパラメータであることを除いて、他の 方法と同じ呼び出し規約を使用しますコンストラクタまたはデストラクタコールのコンテキストを示す に渡されます。

コンストラクタ呼び出しのフラグパラメータの値がFalseの場合、コンストラクタがインスタンスオブジェクトを通じて呼び出されたか、または継承されたキーワード を使用して が示されます。この場合、コンストラクタは通常のメソッド のように動作します。 コンストラクタコールのフラグパラメータのTrueの値は、コンストラクタが クラス参照によって呼び出されたことを示します。この場合、コンストラクタは、 のインスタンスをSelfによって与えられたクラスを作成し、EAXの新しく作成された オブジェクトへの参照を返します。

デストラクタコールのフラグパラメータでFalseの値を指定すると、デストラクタが継承されたキーワードを使用して呼び出された が示されます。この の場合、デストラクタは通常のメソッドのように動作します。デストラクタ呼び出しのフラグパラメータにTrueの値があると、 デストラクタがインスタンスオブジェクトを通じて呼び出されたことを示します。この場合、 デストラクタは、 が返される直前にSelfによって与えられたインスタンスの割り当てを解除します。

フラグパラメータは、他のすべてのパラメータの前に宣言されたかのように動作します。 レジスタ規約の下では、DL レジスタに渡されます。パスカル規約の下では、それは他のすべての パラメータの前にプッシュされます。 cdecl、stdcall、およびsafecallの規則では、Selfパラメータの直前には がプッシュされています。

出典:official Delphi documentation

ですから、inheritedが呼ばれるところはどこでも、それが安全に処理される、ことを確認することができます。たとえば、フィールドの初期化(0にリセット)は、すべてのコンストラクターが呼び出される前に一度だけ処理されます。

TObject.Createデフォルトのコンストラクタ(inherited行で呼び出されたもの)は、空白ブロックで、何もしません。begin endです。ここではinheritedに電話する必要はありませんが、オブジェクト階層を変更すると後に必要になる可能性があるので、それは良い習慣です。

このinheritedのメソッド(ctype := 2など)内にフィールドが設定されていて、子に設定されている場合にのみ問題が発生する可能性がありますが、これはコンパイラの不具合ではありません。

0

モデル)。ここ

1

継承されたコンストラクタを呼び出す前にいくつかのフィールドを初期化することは必ずしもバグではありません。継承されたコンストラクタは、子孫によってオーバーライドされたいくつかの仮想メソッドを呼び出し、これらの新しい実装は、正しく初期化されるフィールドに依存することがあります。

(これは良いデザインだとは言えませんが、バグではありません)

関連する問題