5

次の Java コードを考えてみましょう。

int N = 10;
Object obj[] = new Object[N];
for (int i = 0; i < N; i++) {
    int capacity = 1000 * i;
    obj[i] = new ArrayList(capacity);
}

Java ではすべてのオブジェクトがヒープ上に存在するため、配列にはオブジェクト自体は含まれず、オブジェクトへの参照が含まれます。また、配列自体もオブジェクトであるため、ヒープ上に存在します。

new と delete をできるだけ必要としないようにするために、配列とオブジェクトをスタックに保持する C++ で同等のものは何ですか?

編集: カスタム コンストラクターを使用するようにコードを変更しました。

4

6 に答える 6

5

単純に宣言する

Object array_of_objects[10];

C++ では、スタック上に Object 型のデフォルトで構築されたオブジェクトを 10 個作成します。

デフォルト以外のコンストラクターを使用する場合、C++ ではそれほど簡単ではありません。新しい配置で方法があるかもしれませんが、私は頭の上からあなたに言うことができませんでした.

編集: StackOverflow の他の質問へのリンク 配列に新しい配置を使用する方法は、 StackOverflow のこの質問への回答で説明されています。

于 2008-11-26T12:20:42.537 に答える
4

割り当ては、'静的に' (コンパイル時に既知のサイズ) または '動的に' (実行時に決定されるサイズ) 行うことができます。

静的割り当ては昔からある

int myarray[10];

スタックに割り当てるには、alloca基本的にスタック ポインターをインクリメントするだけの割り当て関数が必要です。(またはデクリメント...何でも)。割り当て解除は自動的に行われます。

int* myarray = (int*) alloca( n*sizeof(int) );

したがって、 Nilsが示したように、スタック上の配列を初期化できます。

std::vector vectorスタック アロケータ ( の 2 番目の面倒なテンプレート引数)が提供されている場合、スタックで動作できます。

私の推測では、Boost はまさにこれを行います。

于 2008-11-26T12:38:06.560 に答える
4

C++ では、実行時に決定されるサイズの配列をスタック上に置くことはできません。ここでは、std::vector を使用してそれを行います。

int N = 10;
std::vector<Object> obj(N);
// non-default ctor: std::vector<Object> obj(N, Object(a1, a2));
// now they are all initialized and ready to be used

コンパイル時にサイズがわかっている場合は、単純な配列をそのまま使用できます。

int const N = 10;
Object obj[N];
// non-default ctor: Object obj[N] = 
//     { Object(a1, a2), Object(a2, a3), ... (up to N times) };
// now they are all initialized and ready to be used

ブーストの使用が許可されている場合は、コンテナーのように反復子を提供し、.size() を使用してそのサイズを取得できるため、boost::array を使用することをお勧めします。

int const N = 10;
boost::array<Object, N> obj;
// non-default ctor: boost::array<Object, N> obj = 
//     { { Object(a1, a2), Object(a2, a3), ... (up to N times) } };
// now they are all initialized and ready to be used
于 2008-11-26T12:21:27.730 に答える
3

ArrayList オブジェクトの配列の場合:

ArrayList obj[10];

オブジェクトはデフォルトで初期化されます。これはユーザー定義型には適していますが、組み込み型には必要ない場合があります。

以下も考慮してください。

std::vector<ArrayList> obj(10, ArrayList());

これにより、2 番目のパラメーターとして渡したものをコピーすることで、オブジェクトが初期化されます。したがって、それらはすべて同じですが、必ずしもデフォルトではありません。また、litb が指摘しているように、ベクトルの「10」は非定数式に置き換えることができますが、配列宣言の「10」は置き換えることができません。

これは、実際には ArrayList オブジェクトをスタックに置くのではなく、ヒープから 10 個すべてを 1 つの割り当てに入れます。したがって、単一の割り当てを本当に余裕がない場合は、パフォーマンスの問題が発生することはほとんどありません。ただし、std::vector はスタック上にあり、破棄されると使用するヒープ オブジェクトはすべて削除されます。そのため、リソースが確実に解放されるようにするために、ベクターはすべてがスタック上にあるかのように動作します。

Java コードの例のように、Object のコンテナと ArrayList 値を混在させると、C++ では危険にさらされることに注意してください。基本的に、ArrayList が Object を拡張したとしても、配列には 10 個のオブジェクトのストレージしか含まれず、ArrayList は Object よりも多くのバイトを格納する必要があるため、これを行うことはできません。その結果、配列にコピーしようとする ArrayList はすべて「スライス」されます。その表現の最初の部分だけが配列に入れられます。

オブジェクトを含むと言っているが、実際には ArrayList を含むタイプのコンテナーが必要な場合は、ポインターのコンテナーが必要です。適切なリソース処理を行うには、おそらくスマート ポインターのコンテナーが必要であることを意味します。

于 2008-11-26T12:22:05.297 に答える
2

スタックに可変数のオブジェクトを割り当てることもできます。ただし、そのためには C と C++ を混在させる必要があります。

// allocate storage for N objects on the stack
// you may have to call _alloca and include something to use this.
object * data = (object *) alloca (N * sizeof (object));

// initialize via placement new.
for (int i=0; i<N; i++)
  new (&data[i])();

コードはテストされていませんが、原則としてそのように動作します。

于 2008-11-26T12:28:04.567 に答える
0

Qt を使用している場合は、QVarLengthArrayを使用できます。

2 番目のテンプレート パラメーターとしてサイズを取り、そのサイズの配列を静的に割り当て、それを std::vector や QVector のようなヒープの代わりに配列のバッキングとして使用します。テンプレートで指定されたサイズを超えて追加すると、代わりにヒープ割り当てが使用されます。

例:

//the following ints will all be stored on the stack,
//and a heap allocation is never performed to store the array
QVarLengthArray<int, 10> objArray;
for (int i = 0; i < 8; i++) {
    int capacity = 1000 * i;
    objArray.push_back(capacity);
}

//since it's a class and not a raw array, we can get the array's size
std::cout << objArray.size(); //result is 8

//a heap allocation will be performed if we add an eleventh item,
//since the template parameter of 10 says to only statically allocate 10 items
objArray.push_back(0); //9 items
objArray.push_back(0); //10 items
objArray.push_back(0); //11 items - heap allocation is performed

テンプレート パラメーターのサイズを下回れば、ヒープ割り当てによるパフォーマンスへの影響を回避できます。動的に割り当てられたスタックベースの配列が効果的に得られます。唯一の欠点は、テンプレート パラメーターで指定された数と正確に同じ数のアイテムを使用しないと、メモリが無駄になることです。使用するアイテムが少なすぎると、空のスペースが無駄になります。使用量が多すぎると、スタックに割り当てられた領域全体が無駄になります。

メモリと引き換えにパフォーマンスを犠牲にする価値がある場合もあれば、そうでない場合もあります。このクラスをやみくもに使用しないことをお勧めします。プロファイリングで std::vector のヒープ割り当てがプログラムのボトルネックの 1 つであることを知っている場合にのみ使用してください。

于 2013-12-03T19:09:03.173 に答える