6

静的配列の基本的なルールは誰もが知っています。

int size = 20;
char myArray[size];

合法ではありません。と。

const int size = 20;
char myArray[size];

大丈夫です。

しかし、これはどうですか。

int f(const int size)
{
    char myArr[size];
}

void main()
{
   f(2);
   f(1024);
}

MSVCはそれがエラーであると言います、gccはそれをうまくコンパイルして実行するようです。

明らかに、それはポータブルではありませんが、それは受け入れられるべきですか?

その状況で正しいことを行うコンパイラはどれですか?

また、コンパイラーによって許可されている場合、適切なプログラミング標準/プラクティスによって許可されるべきですか?

編集済み:速度に応じてスタックを割り当てたいという考えですが、コンパイル時に配列のサイズがわかりません。他にもいくつかの解決策があり、スタック割り当てはおそらく重要な最適化ではないことを私は知っていますが、それは興味深い使用法だと思います。

4

5 に答える 5

9

いいえ。C++には可変長配列はありません。C99はそうします、そしてgccは拡張を介してそれを許可します。

を使用しstd::vectorます。


アプリケーションのプロファイルを作成し、これがボトルネックであることがわかった場合は、スタックから割り当てるカスタムアロケーターを作成して使用します。そうでなければ、問題はありません。

スタックの割り当ては非常に高速ですが、実際のアプリケーションではこれが主な問題になることはないでしょう。(スタック割り当てに近い速度でパフォーマンスを発揮するカスタムメモリ管理スキームを導入する必要があります。)

于 2010-10-22T14:21:18.903 に答える
3

これにはstd::arrayを使用できます。std :: arrayはTR1拡張機能に追加され、使用しているコンパイラ/標準ライブラリのバージョンに応じて、名前空間stdまたはstd::tr1で使用できます。

#incldue <array>
int main()
{
   std::tr1::array<int,25> myArray;
   //etc...
   myArray[2] = 42;
}

スタック割り当てに関する質問を読み直してください...

スタック割り当てが必要な場合は、mallocの代わりにallocaを使用してスタックに割り当てることができます(通常の警告がすべて適用されます)。

より親しみやすいインターフェースが必要な場合は、allocaに基づいてカスタムstlアロケーターを実装し、これでstd :: vectorを使用できます(実装する前に確認する必要があります)。

例えば:

#include <vector>
template <class T>
class MyStackAllocator
{ // implemented per std::allocator spec
...
}
int main()
{
//allocate a vector on the stack and reserve n items
vector<int, MyStackAllocator<T>> vecOnStack(25);
...
}
于 2010-10-22T14:38:15.733 に答える
1

可変長配列(VLA)はC99でサポートされていますが、C++ではサポートされていません。gccは拡張機能を介してそれを許可します。

std::vectorはC++でVLAがC99で行っていることを行っています

于 2010-10-22T14:54:24.790 に答える
1

正解は実際にこのスレッドで提供されたので、私はそれにもっとコンテキストを提供したいと思います。

動的なスタック割り当てにalloca()(またはWindowsで)関数を使用するカスタムアロケータを作成する必要があります。_alloca()作成は非常に簡単です。手動のスタック割り当て解除がないため、一般的なアロケータボイラープレートを使用し、allocate()メンバー関数をに変更して、関数を空にすることができますreturn (pointer)(alloca(size * sizeof(T)));deallocate()その後、アロケータを標準のコンテナに供給することができますvector<T, stack_allocator<T>>

ただし、2つの注意点があります。割り当て可能なスタックサイズは大幅に異なる可能性があり、多くの場合、コンパイル時に設定するオプションがあります。32ビットアプリケーションのVisualStudioは、デフォルトで1MBに制限されていると思います。他のコンパイラには異なる制限がある場合があります。64ビットアプリケーションでは、スタックがヒープと同じくらい大きくなる可能性があるため、実際には問題はありません。おそらく、スタックオーバーランで構造化例外をキャッチし、それをC++例外に変換する必要があります。

2つ目の注意点として、スタックポインタを関数の外部にコピーしないでください。たとえば、スタックに割り当てられたオブジェクトを関数との間で受け渡す場合、移動セマンティクスは機能しません。

また、不便な点が1つあります。互換性のないアロケータを使用してコンテナをコピーすることはできませんが、要素ごとにコピーすることはできます。例えば

vector<int> vint;
vector<int, static_allocator<int>> vsint;

vint = vsint; // won't compile, different allocators
std::copy(vsint.begin(), vsint.end(), vint.begin()); // fine
于 2010-10-29T17:35:35.437 に答える
0

あなたが本当に望んでいるのは、あなたが求めたものではありません。インデックス2042が値23などを保持するように、数値から数値へのマップが本当に必要なようです。

使用する可能性のある最大数の上限が実際にはわからないため、(数学的な)マップを使用するようにコードを再構築する必要があります。ここで、2042のインデックスを考慮する代わりに配列を保持している場合、値23にアクセスするためのキーは2042と見なします。

----実行時定数が以下の静的配列を割り当てることができますか---

init()実行時の静的配列が必要な場合は、代替ポインター構文を使用して配列を宣言し、プログラム実行の開始時に非静的のような関数で初期化するのが最善のオプションです。

実行前に配列を割り当てようとすると、main(...)どの静的ブロックのコードがどの順序で呼び出されるのかわからなくなるリスクがあります。時にはそれはほとんど違いがありません。ただし、あなたの場合、実行時に数値を計算する必要があるように思われるため、モジュールの順序が重要になります。

非静的メソッドを使用することにより、配列を割り当てる前にすべての静的コードが実行されることを基本的に保証します。

于 2010-10-22T14:23:05.213 に答える