web-dev-qa-db-ja.com

C ++で動的に配列を拡張する方法は? {ベクトルのように}

言いましょう、私は持っています

int *p;
p = new int[5];
for(int i=0;i<5;i++)
   *(p+i)=i;

次に、6番目の要素を配列に追加します。どうすればいいのですか?

15
Varrun Ramani

配列を再割り当てしてデータをコピーする必要があります:

int *p;
p = new int[5];
for(int i=0;i<5;i++)
   *(p+i)=i;

// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
27
Kim Gräsman

できません。このためには、STLベクターなどの動的コンテナーを使用する必要があります。または、より大きな別の配列を作成し、最初の配列からその配列にデータをコピーすることもできます。

その理由は、配列がメモリ内の連続した領域を表すためです。上記の例では、pがアドレス0x1000を指し、5つの整数が20バイトに対応しているため、配列が0x1014の境界で終了するとします。コンパイラは、0x1014から始まるメモリに他の変数を自由に配置できます。例えば、 int iは0x1014..0x1018を占める場合があります。次に、配列を拡張してさらに4バイトを占有すると、どうなるでしょうか。

8
Crashworks

mallocを使用して初期バッファーを割り当てる場合、reallocを使用してバッファーのサイズを変更できます。 realloc- edバッファーのサイズ変更にnewを使用しないでください。

int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);

ただし、これはC風の方法です。 vectorの使用を検討してください。

3
Mehrdad Afshari

どうしてvectorがソースを調べてみませんか?このメカニズムの実装は、C++インクルードファイルが存在するフォルダーで確認できます。

これはgcc 4.3.2で何をするかです:

  1. ベクトルのアロケータを使用して、メモリの新しい連続したチャンクを割り当てます(ベクトルは_vector<Type, Allocator = new_allocator>_?であることを覚えています)。デフォルトのアロケータはoperator new()を呼び出して(new!だけではありません)、このチャンクを割り当てます。これにより、_new[]_/_delete[]_のものをいじらないようになります。

  2. 既存の配列の内容を新しく割り当てられた配列にコピーします。

  3. 以前に整列されたチャンクをアロケーターで破棄します。デフォルトではoperator delete()を使用します。

(独自のベクトルを作成する場合、サイズは「固定量」ではなく「M倍」に増加する必要があることに注意してください。これにより、一定の償却期間を達成できます。たとえば、サイズ制限。ベクトルが2倍になり、各要素は平均して1回コピーされます。)

2
P Shved

他の人が言っているのと同じですが、配列のサイズを頻繁に変更する場合は、サイズを2倍にすることで、毎回配列のサイズを変更する方法があります。常に新しいものを作成し、古いものを破壊することには費用がかかるため、2倍化理論は、将来の要素にも十分な余地があることを保証することによって、この問題を軽減しようとします。

1
Glenn