変数intを受け取るメソッドがあります。その変数は配列サイズを構成します(ベクトルを提供しないでください)。したがって、特定のサイズの配列を初期化するには、メソッド内でconstintを初期化する必要があります。質問:どうすればいいですか?
void foo(int variable_int){
int a[variable_int] = {0}; //error
}
変数intを受け取るメソッドがあります。その変数は配列サイズを構成します(ベクトルを提供しないでください)。したがって、特定のサイズの配列を初期化するには、メソッド内でconstintを初期化する必要があります。質問:どうすればいいですか?
void foo(int variable_int){
int a[variable_int] = {0}; //error
}
非ベクトルソリューションを要求しましたが、間違った理由で拒否した可能性があるため、それを調べてみましょう。パフォーマンスについて心配する必要はありません。有能なコンパイラを使用すると、他の標準準拠のソリューションとほぼ同じオーバーヘッドが発生するからです。一方で、読みやすさと安全性に関する懸念事項がいくつかあります。これについては以下で説明します。最も推奨されるものから最も少ないものまで、それを実行できる方法を見てみましょう。
コミュニティのお気に入りのコンテナであり、正当な理由があります。実行時のサイズで宣言できるだけでなく、いつでもサイズを変更できます。これにより、ユーザー入力を繰り返しポーリングする場合など、サイズを事前に決定できない場合に使用しやすくなります。例:
// Known size
size_t n;
std::cin >> n;
std::vector<int> vec(n);
// Unknown size
std::vector<int> vec;
int input;
while (std::cin >> input) { // Note: not always the best way to read input
vec.push_back(in);
}
を使用することにはそれほどマイナス面はありませんstd::vector
。既知のサイズの場合は、1つの動的割り当てが必要です。一般的なケースでは、サイズが不明な場合はさらに多くのことが必要になりますが、とにかくこれ以上のことはできません。したがって、パフォーマンスは多かれ少なかれ最適です。
意味的には、実行全体で一定のサイズには理想的ではない場合があります。このコンテナが変更されることを意図していないことは、読者には明らかではないかもしれません。コンパイラにも知られていないので、論理的に一定のサイズのに何か間違ったことpush_back
をすることができます。vector
静的サイズを適用することが重要な場合の最も安全なソリューション。
size_t n;
std::cin >> n;
auto arr = std::make_unique<int[]>(n);
arr
のサイズは変更できませんが、現在の配列を解放して、異なるサイズの別の配列を指すようにすることはできます。したがって、論理的にコンテナのサイズが一定である場合、これは意図をより明確に伝えます。std::vector
残念ながら、それは一定サイズの場合よりもはるかに弱いです。サイズを認識しないため、サイズを明示的に保存する必要があります。同じ理由で、イテレータを提供せず、範囲forループで使用することはできません。これらの機能を犠牲にして静的サイズを適用するかどうかは、あなた(および問題のプロジェクト)次第です。
最初はお勧めしboost::scoped_array
ましたが、さらに考えた後、このソリューションで提供できるものはあまりないと思います。そのため、標準ライブラリを使用します。
技術的には解決策ですが、古いC ++標準を使用せざるを得ない場合や、内部でメモリを管理する低レベルのライブラリを作成している場合を除いて、std::unique_ptr
またはstd::shared_ptr
ソリューションよりも厳密に劣ります。これらはそれ以上の機能を提供しませんが、使い終わったらメモリを明示的に解放する必要があるため、安全性は大幅に低下します。そうしないと、リークが発生し、重大な問題が発生する可能性があります。さらに悪いことにdelete[]
、実行と例外処理のフローが複雑なプログラムでは、適切に使用することは簡単ではありません。上記の解決策が利用できる場合は、これを使用しないでください。
size_t n;
std::cin >> n;
int* arr = new int[n];
...
// Control flow must reach exactly one corresponding delete[] !!!
delete[] arr;
一部のコンパイラは、実際には次のコードで問題ない可能性があります
size_t n;
std::cin >> n;
int arr[n];
これに依存することには重大な欠点があります。コードをすべてのC++準拠コンパイラでコンパイルできるわけではありません。おそらく、指定されたコンパイラのすべてのバージョンでコンパイルされるわけではありません。また、生成された実行可能ファイルがn
必要に応じてヒープの値をチェックして割り当て、スタックを爆破できるとは思えません。このソリューションは、の上限n
が小さいことがわかっていて、パフォーマンスが非常に重要であり、コンパイラ固有の動作に依存してそれを取得する場合にのみ意味があります。これらは本当に例外的なケースです。
int *a = new int[variable_int];
使い終わったら、割り当てられたスペースを削除[]することを忘れないでください。
C++は可変長配列をサポートしていません。代わりに、配列を動的に割り当てる必要があります。
std::vector<int> a(variable_int);
または、何らかの理由でベクトルを使用したくないと言ったので、次のようになります。
class not_a_vector
{
public:
explicit not_a_vector(size_t size) : a(new int[size]()) {}
~not_a_vector() {delete [] a;}
int & operator[](size_t i) {return a[i];}
int operator[](size_t i) const {return a[i];}
not_a_vector(not_a_vector const &) = delete;
void operator=(not_a_vector const &) = delete;
private:
int * a;
};
not_a_vector a(variable_int);
更新:質問は「C」タグと「C++」で更新されました。C(1999年以降)は可変長配列をサポートしているため、コードはその言語で問題ないはずです。
非const変数からconst変数を作成するには、次のように記述const int bar = variable_int;
します。ただし、それでは役に立ちません。C ++では、自動ストレージを備えた配列のサイズはコンパイル時定数でなければなりません。変数をコンパイル時定数に変換することはできないため、必要なことは単純に不可能です。
必要に応じて、ポインタを作成し、それを使用して(そして後でそれを)a
メモリを割り当てることができます。または、パラメータがコンパイル時に常に認識される場合は、次のようなテンプレート関数に変換できます。new
delete
foo
foo
template<int n> void foo() {
int a[n] = {0};
}
やりたいことを行うには、動的割り当てを使用する必要があります。その場合、代わりにベクトルを使用することを真剣に提案します。これは、C++で行う「正しい」ことです。
しかし、それでもベクトルを使用したくない場合[なぜ私を超えないのか]、正しいコードは次のとおりです。
void foo(int variable_int){
int *a = new int[variable_int](); // Parenthesis to initialize to zero.
... do stuff with a ...
delete [] a;
}
他の人が示唆しているように、callocを使用することもできます。これは、ゼロに初期化するのと同じ効果がありますが、実際には「c++」ソリューションではありません。
配列を使用している場合は、それらをカプセル化することをお勧めします。
template<typename Type>
class Vector {
//...
};
標準ライブラリには次の実装が付属しています:std :: vector