私はC++を使い始めたばかりで、良い習慣を身に付けたいと思っています。 int
型の配列をnew
演算子で割り当てたばかりの場合、すべてをループせずにすべてを0に初期化するにはどうすればよいですか? memset
を使用するだけですか?それを行う「C++」の方法はありますか?
これはC++の驚くほどあまり知られていない機能です(まだ誰もこれを答えとして与えていないという事実によって証明されています)が、実際には配列の値を初期化するための特別な構文があります:
new int[10]();
must空の括弧を使用することに注意してください。たとえば、(0)
などを使用することはできません(これは、値の初期化にのみ役立つ理由です)。
これは、ISO C++ 03 5.3.4 [expr.new]/15で明示的に許可されています。
タイプ
T
のオブジェクトを作成する新しい式は、次のようにそのオブジェクトを初期化します。...
- New-initializerの形式が
()
の場合、アイテムは値で初期化されます(8.5)。
許可されている型は制限されませんが、(expression-list)
フォームは、配列型を許可しないように、同じセクションの追加の規則によって明示的に制限されます。
Std :: vectorではなく配列が本当に必要な場合、「C++の方法」は次のようになります。
#include <algorithm>
int* array = new int[n]; // Assuming "n" is a pre-existing variable
std::fill_n(array, n, 0);
ただし、実際には、これは実際には各要素を0に割り当てる単なるループであることに注意してください(ハードウェアレベルのサポートを備えた特別なアーキテクチャを除き、実際に別の方法はありません)。
組み込み型の配列を割り当てる方法は多数あり、これらの方法はすべて正しいですが、どちらを選択するかは依存します...
ループ内のすべての要素の手動初期化
int* p = new int[10];
for (int i = 0; i < 10; i++)
{
p[i] = 0;
}
std::memset
から <cstring>
関数を使用する
int* p = new int[10];
std::memset(p, 0, 10);
std::fill_n
アルゴリズムを<algorithm>
から使用する
int* p = new int[10];
std::fill_n(p, 10, 0);
std::vector
containerを使用
std::vector<int> v(10); // elements zero'ed
int a[] = { 1, 2, 3 }; // 3-element static size array
vector<int> v = { 1, 2, 3 }; // 3-element array but vector is resizeable in runtime
割り当てるメモリが何か有用なコンストラクタを備えたクラスである場合、演算子newはそのコンストラクタを呼び出し、オブジェクトを初期化したままにします。
しかし、 POD またはオブジェクトの状態を初期化するコンストラクターを持たない何かを割り当てる場合、1回の操作でメモリを割り当てて、演算子newでそのメモリを初期化することはできません。ただし、いくつかのオプションがあります。
1)代わりにスタック変数を使用します。次のように、1ステップで default-initialize を割り当てることができます。
int vals[100] = {0}; // first element is a matter of style
2)memset()
を使用します。割り当てているオブジェクトが POD でない場合、memsettingするのは悪い考えです。具体的な例の1つは、仮想関数を持つクラスをmemsetした場合、vtableを吹き飛ばし、オブジェクトを使用できない状態のままにすることです。
3)多くのオペレーティングシステムには、必要な処理を行う呼び出しがあります。ヒープに割り当てて、データを何かに初期化します。 Windowsの例は VirtualAlloc()
です
4)これは通常、最適なオプションです。メモリを自分で管理する必要はまったくありません。 STLコンテナを使用して、すべてを一気に割り当てて初期化するなど、未加工メモリで行うこととほぼ同じことを行うことができます。
std::vector<int> myInts(100, 0); // creates a vector of 100 ints, all set to zero
はいあります:
std::vector<int> vec(SIZE, 0);
動的に割り当てられた配列の代わりにベクトルを使用します。利点には、配列を明示的に削除する必要がないこと(ベクトルがスコープ外になると削除される)、例外がスローされた場合でもメモリが自動的に削除されることが含まれます。
編集:以下のコメントを読むことを気にしない人々からのさらなるドライブバイダウン投票を避けるために、この答えがベクトルが常に正しい答えであると言っていないことをより明確にする必要があります。しかし、「手動」で配列を削除するよりも、C++の方が確実です。
現在C++ 11では、一定サイズの配列をモデル化するstd :: arrayもあります(vsは成長できるベクトル)。動的に割り当てられた配列を管理するstd :: unique_ptrもあります(この質問に対する他の回答で回答されているように、初期化と組み合わせることができます)。これらのいずれも、配列へのポインターIMHOを手動で処理するよりもC++の方法です。
std::fill
は1つの方法です。領域を埋めるために2つのイテレータと値を取ります。それ、またはforループは(おそらく)よりC++の方法でしょう。
プリミティブ整数型の配列を特に0に設定する場合、memset
は問題ありませんが、眉をひそめる可能性があります。 calloc
も考慮してください。ただし、キャストのためにC++から使用するのは少し不便です。
私の側では、ほとんど常にループを使用します。
(私は人々の意図を推測するのは好きではありませんが、std::vector
はすべてのものが等しいため、new[]
を使用するよりも望ましいことは事実です。)
いつでもmemsetを使用できます:
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));