65

次のコードは、スタックにオブジェクトを作成します。

Object o;

ヒープ上にオブジェクトを作成するときは、次を使用できます。

Object* o;

o = new Object();

それよりも:

Object* o = new Object();

ヒープ オブジェクトの作成を 2 行に分割し、2 行目でコンストラクタを呼び出す場合 ( )、これは 1 行目 ( ) でポインタがスタック上に作成されたo = new object()ことを意味しますか? オブジェクトをスタックに置くのに対し、スタック上の将来のオブジェクトへのポインターを置きますかObject* o?Object oObject* o

2 番目の質問は、2 行のコードがクラスの外で呼び出されたかどうかに関するものです。私は最近、グローバル変数がスタック/ヒープに含まれているのではなく、実際にはメモリの別の部分に含まれていることを読みました (スタックまたはヒープでの C のグローバル メモリ管理? )。この場合、Object* oメモリのこの他の部分に配置され、ヒープ オブジェクトを指すポインタを作成しますか?

4

7 に答える 7

128

実際、どちらのステートメントもヒープやスタックについて何も述べていません。コード

Object o;

コンテキストに応じて、次のいずれかを作成します。

  • 自動ストレージを持つローカル変数、
  • 名前空間またはファイル スコープの静的変数、
  • 別のオブジェクトのサブオブジェクトを指定するメンバー変数。

これは、オブジェクトが定義されているコンテキストによって格納場所が決定されることを意味します。さらに、C++ 標準では、スタックストレージとヒープ ストレージについて言及していません。代わりに、 auto 、dynamicstaticまたはthread-local のいずれかであるstorage durationについて説明します。ただし、ほとんどの実装では、コール スタックによる自動ストレージと、ヒープによる動的ストレージが実装されています。

したがって、自動ストレージを持つローカル変数がスタック上に作成されます。静的 (およびスレッド ローカル) オブジェクトは通常、スタック上でもヒープ上でもなく、独自のメモリ領域に割り当てられます。また、メンバー変数は、それらが属するオブジェクトが割り当てられている場所に割り当てられます。それらには、それを含むオブジェクトの保存期間があります。

これを例で説明するには:

struct Foo {
    Object o;
};

Foo foo;

int main() {
    Foo f;
    Foo* p = new Foo;
    Foo* pf = &f;
}

オブジェクトFoo::o(つまりo、 class のオブジェクトのサブオブジェクトFoo) はどこに作成されるのでしょうか? 場合によります:

  • foo.o静的ストレージがあるためfoo、静的ストレージを持ち、スタックにもヒープにも存在しません。
  • f.o自動ストレージがあるため、自動ストレージfがあります(=スタックに存在します)。
  • p->o動的ストレージがあるため、*p動的ストレージがあります(=ヒープ上に存在します)。
  • pf->oはを指しているf.oため、 と同じオブジェクトです。pff

実際、上記のpとの両方pfに自動ストレージがあります。ポインターのストレージは、他のオブジェクトのストレージと区別がつかず、コンテキストによって決定されます。さらに、初期化式はポインター ストレージには影響しません。

ポインティー(= ポインターが指すもの) はまったく別の問題であり、あらゆる種類のストレージを参照できます:動的*pであるのに対し、*pf自動です。

于 2012-04-14T20:42:59.457 に答える
14

C++ には、オブジェクトを作成する 3 つの異なる方法があります。

  1. 一時オブジェクトなどのスタックベース
  2. newを使用したヒープベース
  3. グローバル変数や名前空間スコープ オブジェクトなどの静的メモリ割り当て

あなたのケースを考えてみましょう。

Object* o;
o = new Object();

と:

Object* o = new Object();

どちらも同じ形です。これは、ポインタ変数 o がスタック上に作成され (変数が上記の 3 カテゴリに属していないと仮定します)、オブジェクトを含むヒープ内のメモリを指すことを意味します。

于 2014-11-06T10:11:06.650 に答える
5

2 つの形式は 1 つの例外を除いて同じです。一時的に(Object *)、作成と代入が分離されている場合、new は未定義の値を持ちます。未定義のポインターは特に有用ではないため、コンパイラーはそれらを結合して戻す場合があります。これは、グローバル変数には関係ありません (宣言がグローバルである場合を除きます。グローバルな場合は、両方の形式に当てはまります)。

于 2012-04-14T20:36:44.513 に答える
1

A)

Object* o;
o = new Object();

`` B)

Object* o = new Object();

AとBに違いはないと思います。どちらの場合も、oはクラスObjectへのポインタです。ステートメントnewObject()は、ヒープメモリからクラスObjectのオブジェクトを作成します。割り当てステートメントは、割り当てられたメモリのアドレスをポインタoに割り当てます。

ヒープから割り当てられたメモリのサイズは、常にsizeof(Object)+ sizeof(void *)ではなくsizeof(Object)であることに注意してください。

于 2012-04-15T12:59:54.647 に答える
1

どちらの例でも、タイプのローカル変数がObject*スタックに割り当てられています。プログラムで違いを検出する方法がない場合、コンパイラは両方のスニペットから同じコードを自由に生成できます。

グローバル変数のメモリ領域は、静的変数のメモリ領域と同じです。スタック上でもヒープ上でもありません。関数内で変数を宣言することにより、その領域に変数を配置できstaticます。その結果、関数の同時呼び出し間でインスタンスが共有されるようになるため、静的を使用する場合は同期を慎重に検討する必要があります。

これは、実行中の C プログラムのメモリ レイアウトに関する説明へのリンクです。

于 2012-04-14T20:42:29.387 に答える