質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

9399閲覧

C++ 変数がスタック/ヒープどちらに作られるか

sin_250

総合スコア112

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

3グッド

3クリップ

投稿2019/05/10 09:55

スタックとヒープについて、簡単には知っているのですが、
確認したいことがあります。

現在の理解は以下です。

  • 自動変数はスタック、newしたものはヒープ
  • 別の理解として、関数を抜けたら自動で消える変数がスタックにあり、そうではないのがヒープにある
  • スタック上に大きな配列などを作るべきでない

現在扱っているコードで大規模な配列を使用している箇所がありますが、今後さらにデータが大きくなる可能性があるため、
スタックに作られると思しき箇所は修正しようと考えていますが、
以下のサンプルコードで理解が正しいかをご教示頂きたいです。

cpp

1class Hoge { 2private: 3 int x[10000]; // Pattern(A): On-HEAP, but Pattern(B): On-STACK 4public: 5 void foo() { 6 int temp[10000]; // Always On-STACK for both Pattern(A) and (B) 7 return; 8 } 9}; 10 11int main(void) { 12 Hoge* A = new Hoge(); // Pattern(A) 13 Hoge B; // Pattern(B) 14 return 0; 15}
  • メンバ変数のinx x[10000]はクラスの定義の方法(newしたか否か)でヒープかスタックか変化する
  • 関数foo内のint temp[10000]は常にスタックに作られる

と理解しています。 ※コードや数字に特に意味はございません。

いつもお世話になります。
よろしくお願い申し上げます。

abeno2365, takey, atata0319👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

解決済みですが。念の為。**高級言語において「グローバル変数はヒープに置かれる」、「ローカル変数はスタックに置かれる」という決まりはありません。**あくまでも、その傾向が強いだけです。

そもそもスタックとかヒープというのはミドルウェア(os)側の提供するメモリ空間の種類名です。一方、高級言語で書かれたプログラムでは(特殊なAPIを使わない限り)使用するメモリ空間を指定することができません。

コンパイラの都合上、ローカル変数はスタックに置くと処理しやすいわけであって、文法上の決まりがあるわけではありません。

投稿2019/05/10 14:36

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/11 16:16

ご回答ありがとうございます!理解しきれておらず申し訳ありません。それは言語仕様としてそういう決まりがないということか、それとも言語毎には決まっているけど言語によって異なる、ということでしょうか。 例えばC++に限った話でも、コンパイラ依存で(例えばgccかMSVCかで)ある変数がスタックに置かれたりヒープに置かれたりするということでしょうか・・・?
HogeAnimalLover

2019/05/12 06:25

はい。言語毎に特別な仕様が決められていればその通りです。が、普通はそんな決まりありません。ローカル変数はスタックに置かれることが多い、とは言えますが確定ではありません。
pepperleaf

2019/05/12 09:49

ローカル変数をスタックに置かないと、再帰呼び出しの時、苦労するなんてもありますね。昔のFortranはそうだったらしいです。(今は知らない)
guest

0

こんにちは。

自動変数はスタック、newしたものはヒープ

その通りです。

別の理解として、関数を抜けたら自動で消える変数がスタックにあり、そうではないのがヒープにある

そうでないものはヒープ以外に静的領域(グローバル変数領域)があります。

スタック上に大きな配列などを作るべきでない

その通りです。
状況によっては大きな配列を割り当てることも可能ですが、一般にデフォルトでは1MBytesか2MBytes程度しか割り当てられませんし、リンカ・オプション等で大きな領域を割り当てるようにしてもコンピュータによってはメモリが余っていてもスタックは余っていないという状況が発生しますので避けるべきです。

メンバ変数のinx x[10000]はクラスの定義の方法(newしたか否か)でヒープかスタックか変化する
関数foo内のint temp[10000]は常にスタックに作られる

どちらともその通りです!

std::unique_ptr<int[]> x(new int[10000]);とすることで、xはHogeの確保方法に関わらずヒープに確保されます。(なお、元のHogeと違ってこのままではコピーできません。そのかわりムーブできます。)

投稿2019/05/10 11:34

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/10 12:04

理解があっていたようで安心しました。詳細なご回答ありがとうございました。 >そうでないものはヒープ以外に静的領域(グローバル変数領域) 頭から抜けていました。static storageやdynamic storageなどを調べてみて勉強になりました。 >std::unique_ptr<int[]> x(new int[10000]);とすることで、xはHogeの確保方法に関わらずヒープに確保されます。(なお、元のHogeと違ってこのままではコピーできません。そのかわりムーブできます。) 以前のQAでムーブセマンティクスについて勉強させていただいたおかげで、上記すんなり理解できました!
guest

0

ベストアンサー

完全にその理解で合っています。

ところでC++では

cpp

1 Hoge* A = new Hoge(); // Pattern(A) 2 Hoge B; // Pattern(B)

の2択だと一般にPattern(B)のほうが好まれる傾向にあります(スマートポインタ使えとかそういうのはさておき)。

となると、

cpp

1class Hoge { 2private: 3 int x[10000]; 4};

のような設計はstackを大量消費してしまうのであまり良くありません。特にそのクラスをcopyしたりmoveすることを想定するなら避けるべきです。すると一般にstd::vectorをメンバに持つような設計になると思います。
もちろん局所的な最適化の結果このようなクラスを作ることがないわけではないのですが。

投稿2019/05/10 11:39

yumetodo

総合スコア5852

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/10 12:16

いつもお世話になります。ご回答ありがとうございます。 >一般にPattern(B)のほうが好まれる これは、ポインタは見せないに越したことはない、ということでしょうか? 確かに使用者がクラスをAで使うかBで使うかは確約がないので、privateで大きなデータを持つのは好ましくないですね。 vectorだと必ずヒープだと知りませんでした。ありがとうございました。
sin_250

2019/05/11 16:18

拝読しました(いいね押しておきました)。重ねてありがとうございます。
guest

0

スタック領域の枯渇が気になるなら

C++

1class Hoge { 2private: 3 std::vector<int> x; // 領域はheap上に確保される 4public: 5 Hoge() : x(10000) {} 6 ... 7};

ってやればいぃぢゃん。

投稿2019/05/10 11:36

episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/10 12:09

ご回答ありがとうございます。確かに使用時に柔軟にサイズ変更できますね。 この場合、質問のPattern Bの場合もxはヒープなのでしょうか・・・? (ベストアンサーを選んだ後なので、無理してご回答いただかなくても大丈夫です)
sin_250

2019/05/10 12:16

すみません、調べなおしたら、vectorは必ずヒープなのですね! 勉強になりました。ありがとうございます。
guest

0

ローカルで自動作成したブツはスタックに、グローバルで作成したブツはヒープに、と思っておきましょう

まあ、スタックエリアというのはその性質上、あまり大きな領域を確保するものではないため注意しましょう。(せいぜい数M~十数M?)
もちろん、オプションやらなんやらの設定でそのサイズを大きくすることはできますが。。

投稿2019/05/10 10:03

y_waiwai

総合スコア88049

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2019/05/10 11:33

>グローバルで作成したブツはヒープ ふつうC/C++でグローバルと言ったらstatic storageのことを指すんじゃないですかね?紛らわしい用法はいかがなものかと。
sin_250

2019/05/10 12:02

ご回答ありがとうございます。 確かにstatic変数もまた特別であることを忘れていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問