7

C++ でスタックまたはヒープにオブジェクトを割り当てるための経験則を探していました。ここでSOに関する多くの議論を見つけました。多くの人が、それはオブジェクトの寿命に関するものだと言いました。関数のスコープよりも長い寿命が必要な場合は、ヒープに入れます。それは完全に理にかなっています。

しかし、私を混乱させたのは、多くの人が、オブジェクトが小さい場合はスタックに割り当てるということです。オブジェクトが大きい場合は、ヒープに入れます。しかし、オブジェクトを識別する方法が大きいかどうかについて、誰も言いませんでしたか?

以下の質問があります。

  1. オブジェクトが大きいかどうかを識別する方法は?
  2. スタックの最大サイズは?OSごとにスタックサイズが異なる?
  3. ラップするラッパークラスがありますvector<string>。約100アイテムになります。このクラスをスタックに割り当てると、スタック オーバーフローが発生しますか? 私はこれを試しましたが、完全に機能しました。私が何か間違ったことをしているかわからない。
4

6 に答える 6

10

まず、ベクトル (およびすべての STL コンテナー クラス) は常にヒープから割り当てられるため、心配する必要はありません。可変サイズのコンテナの場合、スタックを使用することはほとんど不可能です。

スタック割り当てがどのように機能するか (コンパイル時に、基本的に各オブジェクトのポインターをインクリメントすることによって) を考えると、ベクトル メモリがヒープから取得されることは明らかです。

std::vector<int> myInts;
std::string myString;
SomeOther Class;

// this memory must come from the heap, there's no way it
// can now be allocated on the stack since there are other
// objects and these parameters could be variable
myString = "Some String";
myInts.reserve(256);

再帰関数を使用していない限り、数キロバイトのデータを心配することなくスタックに置くことができます。スタックサイズは (OS ではなく) プログラムによって制御され、デフォルトは 32kb から 1mb の範囲になる傾向があります。ほとんどのデスクトップ ソフトウェアは 1 MB の範囲で提供されます。

個々のオブジェクトが問題になることはほとんどありません。一般に、それらはスタックに対して十分に小さいか、ヒープから内部的に割り当てられます。

オブジェクトが関数に対してローカルである場合、それらをスタックに置きます。そうでない場合は、それらをヒープに置きます。

データの読み込み/並べ替え/操作のために割り当てる大きなバッファーにはヒープを使用します。

于 2009-03-06T02:18:38.500 に答える
4

MSDNによると、スタック サイズのデフォルトは 1mb です。(これは明らかに Msdev 用です)。

記事からわかるように、/F フラグを使用してコンパイル時にスタック サイズを変更できます。

スタックとヒープの使用に関する最初のガイドラインはかなり正確だと思います。一時的なスコープ変数が mb よりも大きい場合は、それをヒープに貼り付けます (おそらく、短期間に大量のメモリを割り当てている理由を尋ねます)。そもそも時間)。

于 2009-03-06T02:16:34.527 に答える
3

スタックに大きなオブジェクトを割り当てることができる唯一の方法は、ある時点で古いスタイルの配列を使用することです。例えば:

void f() {
   char a[1000000];    // big object on the stack
}

struct A {
   char c[1000000];
};

void g() {
   A a;      // another big object on the stack
}

配列を使用しない場合 (使用すべきでない場合)、ほとんどのものがヒープに割り当てられます。

void h() {
   std::string s( 100000 );
}

上記は、ポインタ、サイズ情報などのためにスタックに数バイトを割り当ててから、実際のストレージをヒープに割り当てます。

心配するのはやめましょう!あなたはおそらく正しいことをしています!

于 2009-03-06T02:21:18.917 に答える
1

オブジェクトが大きいかどうかを識別する方法は?

コンパイラ/プラットフォームの組み合わせによって異なります。One True の制限はありません。多くの場合、コンパイラを使用すると、これを調整できます。

スタックの最大サイズは?OSごとにスタックサイズが異なる?

主に上記のとおりです。チューニングの制御が少ない唯一のもの。

ベクトルをラップするラッパー クラスがあります。約100アイテムになります。このクラスをスタックに割り当てると、スタック オーバーフローが発生しますか? 私はこれを試しましたが、完全に機能しました。私が何か間違ったことをしているかわからない。

このラッパーとそのブロック内の他のオブジェクトの合計メモリ要件がスタック フレーム サイズを超えない限り機能します。これは、平均的なストリングシーに依存します。

デバッガーをステップ実行してスタック アドレスを確認することをお勧めします。これにより、幅の開始点がある程度わかります。そしてドキュメンテーション。

于 2009-03-06T02:17:31.357 に答える
1

私が言及するもう1つのポイントはvector<>、それ自体のサイズを変更できる必要があるため、それ自体が十分に大きくなった場合(以下を参照) 、それ自体がスタック変数として宣言されている場合でも、含まれているオブジェクトを格納するためにヒープを使用する必要があるということです。vector<>

[編集] Motti がコメントで指摘しているように、vector<>小さなベクトルの最適化として、スタック割り当てオブジェクト内に少量のスペースを予約することが可能です。その場合、このスペース内に収まるほど小さいベクトルで作業する場合、ヒープの割り当ては必要ありません。(この事前に割り当てられたスペースは、小さなベクトルを扱うときにスペースを無駄にしないように、非常に小さくする必要があります。) とにかく、ベクトルが十分に大きくなると、ヒープでの (再) 割り当てが必要になります。

于 2009-03-06T02:20:53.627 に答える
1

1. オブジェクトが大きいかどうかを識別する方法は?

「サイズ」を使用

class c {
  std::vector<std::string> s;
};

int サイズ = sizeof(c);

私のマシンでは、「サイズ」は 16 バイトです。

2. スタックの最大サイズは? OSごとにスタックサイズが異なる?

わかりませんが、大量のデータを割り当てるのに適した場所ではないことは間違いありません。

3. ベクトルをラップするラッパー クラスがあります。約100アイテムになります。このクラスをスタックに割り当てると、スタック オーバーフローが発生しますか? 私はこれを試しましたが、完全に機能しました。私が何か間違ったことをしているかわからない。

いいえ、std::vector は 100 個のアイテムをヒープに割り当てます。

于 2009-03-06T06:25:41.310 に答える