このタイプのメモリは、ヒープまたはスタックに割り当てられますか?
-
06-07-2019 - |
質問
C ++のコンテキスト(重要ではない):
class Foo{
private:
int x[100];
public:
Foo();
}
私が学んだことから、Fooのインスタンスを次のように作成すると、
Foo bar = new Foo();
次に、配列xがヒープに割り当てられますが、Fooのインスタンスを次のように作成した場合:
Foo bar;
その後、スタック上に作成されます。
これを確認するためのリソースがオンラインで見つかりません。
解決
例を少し変更してください:
class Foo{
private:
int x[100];
int *y;
public:
Foo()
{
y = new int[100];
}
~Foo()
{
delete[] y;
}
}
例1:
Foo *bar = new Foo();
- xとyはヒープ上にあります:
- sizeof(Foo *)がスタック上に作成されます。
- sizeof(int)* 100 * 2 + sizeof(int *)はヒープ上にあります
例2:
Foo bar;
- xはスタック上にあり、yはヒープ上にあります
- sizeof(int)* 100はスタック上にある(x)+ sizeof(int *)
- sizeof(int)* 100はヒープ上(y)
実際のサイズは、コンパイラーとプラットフォームに応じて、クラス/構造体のアライメントにより若干異なる場合があります。
他のヒント
厳密に言えば、標準によれば、オブジェクトはスタックまたはヒープ上に存在する必要はありません。標準では、3種類の「ストレージ期間」が定義されていますが、ストレージの実装方法を正確には規定していません。
- 静的保存期間
- 自動保存期間
- 動的ストレージ期間
通常、自動ストレージ期間はスタックを使用して(ほぼ常に)実装されます。
動的ストレージ期間は通常、ヒープを使用して実装されます(最終的には malloc()
を使用)。ただし、これはコンパイラのユーザーでも上書きできます。
静的ストレージ期間は、一般的にグローバル(または静的ストレージ)と呼ばれるものです。
標準では、これらのことについて述べています(以下は、3.7のさまざまなビットからの抜粋です-ストレージ期間):
静的および自動保存期間 導入されたオブジェクトに関連付けられている 宣言(3.1)および暗黙的に 実装によって作成されました(12.2)。 動的ストレージ期間は で作成されたオブジェクトに関連付けられています 演算子new(5.3.4)。
...
動的ではないすべてのオブジェクト 保存期間もローカルもありません 静的ストレージ期間。ストレージ これらのオブジェクトは プログラムの期間(3.6.2、 3.6.3)。
...
autoが明示的に宣言されたローカルオブジェクト または登録するか、明示的に宣言しない staticまたはexternには自動 保管期間。のストレージ これらのオブジェクトは、ブロックが それらは出口で作成されます。
...
オブジェクトは動的に作成できます プログラム実行中(1.9)、使用 new-expressions(5.3.4)、および破棄 delete-expressions(5.3.5)を使用します。交流 + +実装により、動的ストレージへのアクセスと管理を提供します。 グローバル割り当て関数 operator newおよびoperator new []および グローバルな割り当て解除関数 operator deleteおよびoperator delete []。
...
ライブラリはデフォルトを提供します グローバル割り当ての定義 および割り当て解除関数。一部 グローバルな割り当てと割り当て解除 関数は交換可能です(18.4.1)
そして最後に(例のクラスの配列に関して):
3.7.4サブオブジェクトの期間[basic.stc.inherit]
メンバーサブオブジェクト、ベースクラスサブオブジェクト、および配列要素の保存期間は、それらの完全な保存期間です オブジェクト(1.8)。
Foo型のオブジェクトは、順番に格納された100 intのサイズを取ります。 スタック上に作成すると、すべてスタック上に作成されます。 newで実行すると、オブジェクトの一部としてヒープ上に配置されます。
これは言語仕様の一部です。あなたの質問が何であるかわかりません。
はい、ヒープに Foo
オブジェクトを作成すると、ヒープにメンバー配列 x
が作成されます。 Foo
に動的メモリを割り当てるとき、長さ sizeof(Foo)
のメモリを要求しています(さらにメモリオーバーヘッドも可能ですが、とりあえずそれを無視しましょう)。サンプルコードでは、100個の int
sのサイズを示しています。この は、 Foo
型のオブジェクト(およびその内部データ)の寿命がスコープを超えている場合に当てはまります。
ヒープに Foo
オブジェクトを作成せず、 Foo
の内部配列がでメモリを割り当てるポインタではない場合
を指定すると、その内部配列がスタック上に作成されます。繰り返しますが、これは、スコープが終了したときに Foo
のコンストラクタでnew delete
sなしで配列が自動的にクリーンアップされるためです。具体的には、
struct Foo {
int* y;
Foo() : y(new int()) { }
~Foo() { delete y; }
};
は、 Foo
オブジェクトがスタック上またはヒープ上に作成されたかどうかに関係なく、ヒープ上に y
を作成します。
という意味
Foo* bar = new Foo();
そうですね。ヒープ内にそれが作成されます。