int
実際には、この関数はs の配列 (すなわち)を返しませんint[N]
。返されるのはint
( int *
) へのポインターです。s
このポインターは、 型の要素の配列の最初の要素を指していることがわかりますint
。
メモリが次のように割り当てられていることに注意してくださいnew
。
int *ret = new int[s];
したがって、 がint
指す sの配列には、ret
動的なストレージ期間があります。とりわけ、これは次のことを意味します。
1) コンパイラは、各配列要素のデストラクタを自動的に呼び出しません。(この場合、要素は型であるため、これは問題ではありませんがint
、代わりに、非自明なデストラクタを持つクラス型の要素の場所である可能性があります。)
2) コンパイラは、割り当てられたメモリを自動的に解放しません。
対照的に、次のコードを検討してください。
void g() {
int p[10]; // allocates 10 integer in the stack
// use p ...
}
がg
終了すると、コンパイラは前述の操作を実行します。これを機能させるには、配列のサイズ (この例では 10) をコンパイル時に設定する必要があります。new
元のコードのように、コンパイル時に必要なサイズがわからない場合。
動的に割り当てられた配列の場合、配列が不要になったときに前述の 2 つの操作が確実に実行されるようにするのはプログラマの責任です。これを行うには、次を呼び出す必要がありますdelete[]
。
delete[] p; // where p is a `int*` with the same value as `ret`
実際には、例外がスローされる可能性があるため、これは見かけよりも困難です。たとえば、このコードを考えてみましょう
void foo() {
int* p = f(10); // where f is in the question
// ... use the array pointed by p
a_function_that_might_throw();
delete[] p;
}
が例外をスローした場合、実行は削除されa_function_that_might_throw
た時点に到達しません。p
この場合、new
(inside f
) によって割り当てられたメモリは、プログラムが終了するまで解放されません (リークします)。
この問題を回避するには、生のポインター (例: int*
) の代わりに、スマート ポインター (例:std::unique_ptr
またはstd::shared_ptr
) を使用することをお勧めします。
最後に、デフォルトでは、によって割り当てられるnew
メモリはヒープ メモリです。ただし、この動作は変更できます。