2012-01-14 6 views
8

これは私をしばらく困惑させています。これは、静的および動的メモリ割り当ての違いを私が理解していないという心臓部に向かいます。次の配列は通常の静的配列です。つまり、コンパイル時にメモリが割り当てられているはずです。それでも、ユーザが実行時に配列サイズを入力するように設定しました。何newまたはdelete事業者がこのプログラムに存在しないことを配列は静的ですが、配列サイズは実行時まで認識されません。これはどのように可能ですか?

#include <iostream> 
using namespace std; 

int main() { 
    cout << "how many elements should the array hold? "; 
    int arraySize; 
    cin >> arraySize; 

    int arr[arraySize]; 

    for (int i = 0; i < arraySize; ++i) 
    arr[i] = i * 2; 

    return 0; 
} 

注意。私の学校のUNIXサーバ(GCC 4.4.5)だけでなく、Xcode 4.2(デフォルトのClangコンパイラ)でも正常に動作します。コンパイル時に配列が作成されたときに、どのくらいの量のメモリを割り当てようとしますか?これは私のコンパイラ、他のメモリを壊す可能性のある危険なコード、またはこの正当なものですか?

+1

:警告が生成されます-pedanticでコンパイルするgccのために

、。 –

+3

'g ++ -Wall -Wextra -pedantic -std = C++ 98'のコンパイルを試してください –

答えて

8

これはC++コンパイラの非標準拡張です。 Cでは、C++とは異なり、C99以降、これは正式にサポートされています(つまり、標準で強制される動作)。 C++では、すでに問題の解決策があるため、サポートされていません。配列の代わりにstd::vectorを使用してください。

ただし、配列はではありません。ではなく、静的メモリ割り当て(動的メモリ割り当て)ではなく自動メモリ割り当てです。自動変数は、関数の最後に自動的に割り当てが解除されます(割り振られたメモリー領域は、スタックの割り振りと割り振り解除にスタック・セマンティクスがあるため、スタックと呼ばれます)。配列に静的メモリ割り当てを使用させるには、定義の前にstaticを置く必要があります(グローバルまたは名前空間スコープの変数は常に静的メモリ割り当てを使用します)。ただし、変数を静的にすると、コンパイラーは非定型配列サイズを使用できなくなります。

std::vectorは、ダイナミックメモリ割り当てでデータを格納することに注意してください。そのため、静的サイズでも一定でないサイズを使用することもできます(std::vector)。

+0

それが許されない主な理由は、ベクトルの代替があるということではありません。配列のサイズが型の一部であり、コンパイル時に知っていなければならないという事実として、より深刻な理由があります。 –

+0

@DavidRodríguez-dribeas:Cの長さの配列がCの規則の例外を必要とするのと同じように、それらの規則を例外にすることができました。 – celtschk

0

Variable Length Arrayです(C99でのみサポートされ、Cではサポートされていません)。実行時にスタックに割り当てられます。

+0

これは有効なC++ですか? IIRCでは、Visual Studioにこれに関するいくつかの誤りがありました。 – stativ

+0

stativは正しいです。これはC++ではありません。 –

+0

いいえ、動的メモリ割り当てではありません。自動メモリ割り当てです。 @stativ:いいえ、それは有効なC++ではありません(ただし、C++固有のコードに囲まれていない場合は有効です)。 C++では、コンパイラの非標準的な拡張です。 – celtschk

1

生成されたコードは、実行時にスタック上にarraySizeバイトを割り当てます。関数が返ってくると、配列の配列に割り当てられたバイトを「返す」など、スタックは巻き戻されます。

newとdeleteを使用すると、ヒープに領域を割り当てることができます。ヒープ上で割り当てられたメモリの有効期間は、関数またはメソッドのスコープとは無関係です。関数内でスペースを割り当てて関数が返っても、メモリは引き続き割り当てられ、有効です。

4

関数内で宣言された配列(または任意のオブジェクト)に対して、メモリは関数へのエントリ時に(通常はスタック上に)割り当てられ、関数が復帰すると割り当てが解除されます。この場合、関数がmainであるという事実は影響を与えません。

これ:

cin >> arraySize; 
int arr[arraySize]; 

"は可変長配列"(VLA)です。つまり、C++はVLAをサポートしていません。 Cは、1999年のISO C標準(C99)から始まりましたが、C++が採用した機能ではありません。

コンパイラは、拡張機能としてC++でVLAをサポートしています。それらを使用すると、コードは移植できなくなります。

(VLAの問題の1つは、割り当てエラーを検出するメカニズムがないため、arraySizeが大きすぎるとプログラムの動作が不定です)。これは、C99にデビュー_variable長arrays_と呼ばれる機能を使用しています

warning: ISO C++ forbids variable length array ‘arr’ 
関連する問題