私はC ++を始めたばかりで、いくつかの良い習慣を身につけたいと思っています。私はちょうど型の配列を割り当てられている場合int
とnew
オペレータ、どのように私はそれらをすべて自分自身をループせずに0にそれらのすべてを初期化することができますか?私は使うべきmemset
ですか?それを行う「C ++」の方法はありますか?
&vector[0]
ます。
私はC ++を始めたばかりで、いくつかの良い習慣を身につけたいと思っています。私はちょうど型の配列を割り当てられている場合int
とnew
オペレータ、どのように私はそれらをすべて自分自身をループせずに0にそれらのすべてを初期化することができますか?私は使うべきmemset
ですか?それを行う「C ++」の方法はありますか?
&vector[0]
ます。
回答:
これは驚くほど知られていないC ++の機能です(まだ誰も答えを出していないという事実からも明らかです)が、実際には配列の値を初期化するための特別な構文があります。
new int[10]();
空の括弧を使用する必要があることに注意してください。たとえば、(0)
その他を使用することはできません(これが値の初期化にのみ役立つ理由です)。
これは、ISO C ++ 03 5.3.4 [expr.new] / 15によって明示的に許可されています。
タイプのオブジェクトを作成するnew-expressionは、
T
そのオブジェクトを次のように初期化します。...
- new-initializerの形式がの
()
場合、アイテムは値で初期化されます(8.5)。
また、これが許可されているタイプを制限しませんが、(expression-list)
フォームは同じセクション内の追加のルールによって明示的に制限されているため、配列タイプは許可されません。
new int[10] {}
。次のように初期化する値を指定することもできます。new int[10] {1,2,3}
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, sizeof(int) * 10);
std::fill_n
からのアルゴリズムの使用<algorithm>
int* p = new int[10];
std::fill_n(p, 10, 0);
std::vector
コンテナを使用する
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
int array[SIZE] ={1,2,3,4,5,6,7};
表記法を使用した場合、使用void rotateArray(int (& input)[SIZE], unsigned int k);
できるのは関数宣言ですが、最初の規則を使用するとどうなりますか?なにか提案を?
std::memset
が間違っていると思います-10を渡すと、バイト数を期待するようです-en.cppreference.com/w/cpp/string/byte/memsetを参照してください。(これは、なぜこのような低レベルの構成を避ける必要があるのかをうまく示していると思います。)
割り当てるメモリが、何か便利なコンストラクタを持つクラスである場合、new演算子はそのコンストラクタを呼び出し、オブジェクトを初期化したままにします。
しかし、PODを割り当てる場合、オブジェクトの状態を初期化するコンストラクターを持たないまたは何かをは、メモリを割り当てて、1回の操作でnew演算子を使用してメモリを初期化することはできません。ただし、いくつかのオプションがあります。
1)代わりにスタック変数を使用します。次のように、1つのステップで割り当てとデフォルトの初期化を行うことができます。
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では、一定サイズの配列(vsベクトルを拡張できる)をモデル化するstd :: arrayもあります。動的に割り当てられた配列を管理するstd :: unique_ptrもあります(この質問に対する他の回答で回答されている初期化と組み合わせることができます)。これらのいずれも、配列へのポインターを手動で処理するよりもC ++の方法です。
std::vector
動的に割り当てられた配列の代わりに常に使用する必要がありますか?ベクトルではなく配列を使用する利点は何ですか?
std::vector
です。
vector
コンテキストに関係なくどこにでも留まることを「C ++でJavaコードを書く」と呼びます。
std::fill
片道です。2つのイテレータと1つの値を取り、領域を埋めます。それ、またはforループの方が(おそらく)C ++のほうがいいでしょう。
特にプリミティブ整数型の配列を0に設定するmemset
ことは問題ありませんが、眉毛を上げる可能性があります。calloc
キャストのため、C ++から使用するのは少し不便ですが、も検討してください。
私の場合、ほとんど常にループを使用しています。
(私は人々の意図を推測するのは好きではありませんstd::vector
が、すべてが同等であり、を使用するよりも望ましいというのは事実ですnew[]
。)
いつでもmemsetを使用できます。
int myArray[10];
memset( myArray, 0, 10 * sizeof( int ));
memset
が、これが問題に取り組むためのC ++の方法であるかどうかはわかりませんでした。
10 * sizeof( *myArray )
よりドキュメント化されており、変更に対応してい10 * sizeof( int )
ます。