2

Delphiの初期化されていない変数は、特定の値を持つことが保証されていますか

  • スタック上?
  • ヒープ上?

C ++ Builderは一般的にDelphiの設計に従っているため、C ++ Builderの初期化されていない変数は、特定の値を持つことが保証されています。

  • スタック上?
  • ヒープ上で、TObjectから派生したクラスのメンバー変数の場合?
  • ヒープ上で、 POCOのメンバー変数の場合?

私は、ゼロで初期化されるメンバー変数に大きく依存するC ++ Builderコードをいくつか継承し、言語がこれを保証するかどうかを理解しようとしています。

Windowsは、メモリがプログラムのスタックまたはヒープに最初に渡されたときに、メモリがゼロで初期化されることを保証しますか?(編集:プログラムは実行時にメモリを上書きするため、これに依存し続けることはできません。私が観察した動作を理解しようとしているだけです。)

4

5 に答える 5

8

caskey の回答は c++ のみに関するものであるため、デルファイに対する私の回答は次のとおりです。

デルファイでは、 Giacomo Degli Espostiによるこの回答を参照してください

  • オブジェクト フィールドは、常に 0、0.0、''、False、nil、または適用されるものに初期化されます。
  • グローバル変数は常に初期化されます。(0まで)
  • ローカル変数は初期化されているため、使用する前に値を割り当てる必要があります。

ms-help://borland.bds4/bds4ref/html/Variables.htm

ジャコモ・デリ・エスポスティのすべてのクレジット

編集:「Windowsは、メモリが最初にプログラムのスタックまたはヒープに与えられたときに、メモリがゼロで初期化されることを保証しますか?

Windows は、メモリが新しいプロセスに最初に与えられたときに、メモリがゼロで初期化されることを保証します (そうしないと、アクセス許可に関係なく、他のプロセスが破棄したメモリをプログラムが読み取ることができるという大きなセキュリティ上の問題が発生します)。ただし、c++ を使用すると、コードがメモリを使用する前に c ランタイムがその裁量でメモリを上書きする可能性があるため、この保証はあまり役に立ちません。

Edit2 : C++ ビルダー変数は、明らかに「VCL スタイル クラス」用に初期化されます (つまり、TObject から継承するものはすべて?) 。 pdf

私は引用します:

「データ メンバーは仮想関数で使用される可能性があるため、それらがいつ、どのように初期化されるかを理解することが重要です。Object Pascal では、初期化されていないデータはすべてゼロで初期化されます。これは、たとえば、コンストラクターが呼び出されない基底クラスに適用されます。In standard C++, there is no guarantee of the value of uninitialized data members.次のタイプのクラス データ メンバーは、クラスのコンストラクターの初期化リストで初期化する必要があります。

ただし、これらのデータ メンバーの値、またはコンストラクターの本体で初期化された値は、基本クラスのコンストラクターが呼び出された時点では未定義です。C++Builder では、VCL スタイル クラスのメモリはゼロで初期化されます。

技術的には、ゼロになるのは VCL または CLX クラスのメモリです。つまり、ビットはゼロであり、値は実際には未定義です。たとえば、参照はゼロです。

コンストラクターの本体または初期化リストで初期化されたメンバー変数の値に依存する仮想関数は、変数がゼロに初期化されたかのように動作する場合があります。これは、初期化リストが処理される前、またはコンストラクタ本体が入力される前に、基本クラスのコンストラクタが呼び出されるためです。

#include <sysutils.hpp>
class Base : public TObject {
public:
    __fastcall Base() { init(); }
        virtual void __fastcall init() { }
    };
class Derived : public Base {
    public:
        Derived(int nz) : not_zero(nz) { }
        virtual void __fastcall init()
        {
        if (not_zero == 0)
        throw Exception("not_zero is zero!");
        }
    private:
        int not_zero;
};
int main(void)
{
    Derived *d42 = new Derived(42);
    return 0;
}

この例では、Base のコンストラクターで例外をスローします。Base は Derived の前に構築されるため、not_zero は、コンストラクターに渡された値 42 でまだ初期化されていません。基本クラスのコンストラクターが呼び出される前に、VCL スタイルのクラスのデータ メンバーを初期化できないことに注意してください。"

于 2009-06-06T14:20:26.893 に答える
2

簡単な答え:C ++では、すべてを初期化する必要があります

C ++BuilderがC++のようなものである場合、明示的に初期化しない限り、メモリの内容に関する保証はありません。

Windowsは、プログラムのスタックまたはヒープで使用できるようになる前にページを空白にする場合がありますが、OSから独自のメモリを要求しない限り、メモリ割り当てにコンストラクタまたはライブラリを使用している可能性があります。はるかに多くの場合、すでに自分で使用しているページまたはメモリ領域を取得します。その場合、それは汚れていることがほぼ保証されています。ほとんど新しいページではないスタックページの場合は、2倍になります。

memset()は、Cでメモリをワイプする方法ですが、C ++では、各フィールドにデフォルト値を指定するか、コンストラクターで明示的に初期化する必要があります。

于 2009-06-06T14:13:13.540 に答える
1

C++ では、メモリは次の状況で初期化されることが保証されています。

  • 静的に割り当てられた変数の場合
  • メンバーを初期化するコンストラクタを持つオブジェクトの場合

これらの最初のケースでは、int、ポインターなどの POD データ型はゼロで初期化されます。

これらは、C++ 標準が提供する唯一の保証です。Windows は、この領域についてまったく保証しません。

于 2009-06-06T14:20:18.813 に答える
1

Delphi では、TObject コンストラクタは、オブジェクトのヒープ割り当てメモリ (Delphi では TObject をスタックでインスタンス化できないため、常にヒープ上) をゼロで初期化し、それによってすべてのメンバー変数をクリアします。

于 2009-06-06T14:30:06.687 に答える