2009-07-24 10 views
1

サイズが6 * sizeof(float)のxという配列があります。清潔さとスピードの点での動的メモリと静的メモリのベストプラクティス

float x[6]; 

は、スタックメモリに6 * sizeof(float)を割り当てます。しかし、私がしなければ、次の

float *x; // in class definition 

x = new float[6]; // in class constructor 

delete [] x; // in class destructor 

は私がxに​​6 *のはsizeof(フロート)の動的メモリを割り当てることになります。クラスの存続期間中にxのサイズが変化しない場合は、クリーンで高速なベストプラクティス(スタックメモリの動作がダイナミックメモリの動作よりも速いのは間違いないと思いますが)を確認する必要がありますそのxは動的に割り当てられるメモリではなく静的に割り振られますか?前もって感謝します。

+1

C++コンテキストの「静的」は、「スタック上」とはまったく異なることを意味します。スタック変数の公式な用語は "自動"で、ヒープ割り当ての変数は "フリーストアから"取られていると思います。 – xtofl

答えて

8

固定サイズの配列を宣言するのは確実に高速です。それぞれの個別の動的割り当てでは、占有されていないブロックを見つける必要があり、それほど高速ではありません。

ダイナミックアロケーションを必要としない場合は、実際にスピードに関心がある場合(プロファイルを作成した場合)、ルールは使用しないでください。もしあなたがそれを必要とするならば、再配分が非常に速くないので、配分する量を2回考えてください。

+0

なぜこの文脈で「静的」という言葉を使用していますか?それは "スタック上"とはまったく異なる何かを意味します... – xtofl

+0

(オハイオ州、それは疑問に思えます...) – xtofl

+0

@xtofl:はい、それはここで使用する幸運な言葉ではありませんでした。一定。 – sharptooth

1

はい、静的に配列を宣言する方が高速です。

これはテストするのが簡単です。これらのオブジェクトのX個のインスタンスを生成する単純なラッピングループを作成するだけです。また、マシンコードをステップ実行して、メモリを動的に割り当てるために必要なOPCODEの数を確認することもできます。

0

構成が効率的で、高速で、メモリオーバーヘッドが少なく、メモリの断片化が少なくなります。

あなたはこのような何かを行うことができます:可能な限り

template <int SZ = 6> 
class Whatever { 
    ... 
    float floats[SZ]; 
}; 
0

は、スタックに割り当てられたメモリを使用してください。それは、メモリの割り当てを解除する頭痛、仮想アドレス空間の断片化などからあなたを救うでしょう。また、それは動的メモリ割り当てに比べて速いです。

0

構造体を静的に割り当てると、インスタンスが1つだけ存在します。クラスを使用するポイントは、複数のインスタンスが必要なことです。配列を動的に割り当てる必要はありません。

class A { 
    ... 
    private: 
     float x[8]; 
}; 

はあなたが望むものです。

+0

"配列を静的に割り当てると、その配列は1つしかありません。クラスを使用するポイントは、複数のインスタンスが必要なことです。 " - Huh?クラスコンストラクタに動的に割り当てられているか、メンバ変数として静的に割り当てられているかにかかわらず、オブジェクトの各インスタンスの配列があります – hobodave

+0

@ hobodave:それは正しくありません。スタックにオブジェクトを割り当てることと、クラス内の静的オブジェクトを割り当てることには違いがあります。Neilが指しているのは、2番目のものです。次に、クラスのインスタンスの数に関係なく、 。 – Naveen

+1

@hobodaveどこにiktが現れても、静的変数はまったく単一のインスタンスを持っています。 –

2

スタック上のTBHデータは、一般にキャッシュに格納され、したがってより高速です。しかし、あなたが何かを一度動的に割り当てて、それを定期的に使用すると、それもキャッシュされ、それゆえにかなり高速です。

重要なことは、定期的に(つまり、関数が呼び出されるたびに)割り当てと割り当て解除を避けることです。通常の割り振りと割り当て解除(つまり、割り振りと割り振り解除を一度だけ行う)を無効にすると、スタックとヒープに割り当てられた配列は、お互いにほぼ同時に素早く実行されます。

3

配列メンバーを使用すると、割り当てや割り当て解除の関数を呼び出す必要がないため、クリーナー(より簡潔でエラーが発生しにくい)で高速になります。また、割り当てられている構造体の「参照の局所性」を向上させる傾向があります。

このようなメンバに動的に割り当てられたメモリを使用する主な理由の2つは、実行時に必要なサイズがわかっているか、または必要なサイズが大きい場合に、利用可能なメモリに大きな影響を及ぼすことがわかっているターゲットプラットフォーム上のスタックスペース。

0

プレイでより多くの変数がここにあります

  1. スタックのサイズ対配列のサイズは、:スタックサイズは、フリーストア(30メガバイト件まで例えば1メガバイト)に比べてかなり小さいものです。大小アレイの数

  2. 配列の寿命:それは唯一の関数内でローカルに必要なの場合、スタックは非常にあるスタック上の大きな塊は、必要な配列のスタックオーバーフロー

  3. が多数発生します便利。 の後に関数が終了した場合は、に割り当てる必要があります。

  4. ガベージコレクション:ヒープに割り当てた場合は、手作業でクリーンアップするか、スマートポインタの風味が必要です。

1

静的割り当ては高速です(メモリに依頼する必要はありません)、あなたはそれを削除したり、不正確なdelete演算子([]削除の代わりに削除)してそれを削除するのを忘れます方法はありません。ダイナミック/ヒープデータの

建設使い方は、以下のステップで構成されています

  • は(new演算子を呼び出す)オブジェクトを割り当てるメモリを求めます。メモリがない場合、new演算子はbad_alloc例外をスローします。
  • (削除/削除[]オペレータによって)ユーザによってメモリを解放する(また、新しいによって行わ)デフォルトコンストラクタ
  • 付きオブジェクトを作成 - 削除するデストラクタをオブジェクトへ を呼び出します。ここでは、ユーザが多くのミスを行うことができます。
    • は削除するために呼び出すことを忘れ - 悪いことが起こるのだろう - これは、メモリにつながる正しくないdelete演算子へ
    • コールを(例えば、[]削除の代わりに削除します)漏れます
    • 呼び出しが二度削除する - 静的オブジェクト/オブジェクトの配列を使用する場合は、悪い事は

が起こることができ、メモリを割り当て、ユーザーがそれを解放する必要はありません。これにより、コードが簡単になり、エラーを起こしにくくなります。

結論として、コンパイル時に配列のサイズを知っていて、メモリについては(実行時には配列のエントリを使用しない)、静的配列は明らかに好ましい配列です。それは価値がある(here

1

スマートポインタを探して、動的に割り当てられたデータについては は、以下の場合を混同しないでください:今

int global_x[6];  // an array with static storage duration 

struct Foo { 
    int *pointer_x;  // a pointer member in instance data 
    int member_x[6]; // an array in instance data 
    Foo() { 
     pointer_x = new int[6]; // a heap-allocated array 
    } 
    ~Foo() { delete[] pointer_x; } 
}; 

int main() { 
    int auto_x[6];   // an array on the stack (automatic variable) 
    Foo auto_f;    // a Foo on the stack 
    Foo *dyn_f = new Foo(); // a heap-allocated Foo. 
} 

auto_fがあるので

  • auto_f.member_xは、スタックにありますスタック上にある。
  • (*dyn_f).member_xはヒープ上にあるため、*dyn_fがヒープ上にあるためです。
  • 両方のFooオブジェクトの場合、pointer_xはヒープ割り当て配列を指します。
  • global_xは、プログラムが実行されるたびにOSまたはランタイムが作成するデータセクションの一部です。これは動的割り当てと同じヒープからのものでも、そうでなくてもかまいませんが、通常は重要ではありません。

のでかかわらず、それは、ヒープ上にあるかどうかの、member_xはので長さは、常に6である場合にpointer_xより良い賭けである:それは少ないコードと少ないエラーが発生しやすいのです

  • オブジェクトが2の代わりにヒープ割り当てされている場合、オブジェクトには1つの割り当てのみが必要です。
  • オブジェクトがスタック上にある場合、ヒープ割り当ては不要です。
  • 割り当てが少なくて済み、またポインタ値の記憶域が不要なため、メモリの使用量が少なくなります。あなたは、オブジェクトの存続期間中に再割り当てする必要がある場合は

    • pointer_xを好む

    理由。

  • 異なるオブジェクトに異なるサイズの配列が必要な場合(おそらくコンストラクタパラメータに基づいて)
  • Fooオブジェクトがスタックに配置されますが、配列が大きすぎてスタックに収まらない場合。たとえば、1MBのスタックがある場合、int[262144]を含む自動変数は使用できません。
0

スタックサイズがわからないため、大きなオブジェクトをスタックに割り当てることはできません。移植性の観点から、可変サイズの大きなオブジェクトまたはオブジェクトは、常にヒープ上に配置する必要があります。

オペレーティングシステムで提供されているmalloc/newルーチン(Solarisのlibumemなど)には多くの開発が行われています。動的メモリ割り当ては、しばしばボトルネックではありません。

関連する問題