std::array
Cアレイよりもはるかに優れています。また、レガシーコードと相互運用したい場合でも、を使用できますstd::array::data()
。オールドスクールアレイが必要になる理由はありますか?
std::array
Cアレイよりもはるかに優れています。また、レガシーコードと相互運用したい場合でも、を使用できますstd::array::data()
。オールドスクールアレイが必要になる理由はありますか?
回答:
私が何かを見逃していない限り(私は標準の最新の変更にあまり厳密に従っていません)、Cスタイルの配列の使用のほとんどはまだ残っています。 std::array
静的な初期化は可能ですが、初期化子はカウントされません。また、以前のCスタイル配列の唯一の実際の使用はstd::array
、次の行に沿って静的に初期化されたテーブルでした。
MyStruct const table[] =
{
{ something1, otherthing1 },
// ...
};
通常の関数begin
とend
テンプレート関数(C ++ 11で採用)を使用してそれらを反復処理します。コンパイラーが初期化子の数から決定するサイズについては言及していません。
編集:私が忘れていたもう一つのこと:文字列リテラルはまだCスタイルの配列です。つまり、タイプchar[]
。私たちが持っているからといって、文字列リテラルの使用を除外する人はいないと思いますstd::array
。
const char[]
いいえ、ああ、率直に言って。そして30文字。
もちろん、を実装するにはC配列が必要ですがstd::array
、ユーザーがC配列を必要とする理由はそれだけではありません。加えて、NO、std::array
Cアレイ未満パフォーマンスはない、との境界確認済みアクセスのためのオプションを有します。そして最後に、どのC ++プログラムも標準ライブラリに依存することは完全に合理的です-それが標準であるということの一種です-標準ライブラリにアクセスできない場合、コンパイラは非準拠であり、質問は「C ++」ではなく「C ++」とタグ付けされています。「C ++とは、不適切だと感じたために仕様の半分を逃したもの」ではありません。
std::array
しかし、独立したC ++ 11実装に実装できないコンパイラーについては、深刻な疑いがあります。
C配列を使用すると、多次元配列を使用する方が簡単ですstd::array
。例えば、
char c_arr[5][6][7];
とは対照的に
std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;
また、C配列の自動減衰プロパティによりc_arr[i]
、上記の例ではポインターまで減衰し、残りの次元をさらに2つのパラメーターとして渡す必要があります。私のポイントは、それがあるc_arr
コピーに高価ではありません。ただし、cpp_arr[i]
コピーには非常にコストがかかります。
array
次元を失うことなく多次元を関数に渡すことができます。そして、それを関数テンプレートに渡すと、その関数は、次元と各次元のサイズの両方、またはそれらの2つのうちの1つだけを推定できます。これは、主に任意の次元で機能する科学テンプレートライブラリにとって興味深いかもしれません。
template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;
これらの問題のいずれかを解決する必要があります。
c_arr
はコピーするのに非常に高価です!そのためには、自分でコードを提供する必要があります。減衰するポインタは、コピーよりも参照に近いものであり、それが必要なstd::array
場合は、参照を渡すために使用できます。
std::size_t
代わりにすべきではありませんint
か?つまらないことを申し訳ありませんが、これはそれを普遍的にするでしょう。
size_t
40億行以上の行または列を持つ配列が必要となるシナリオがたくさんあるとは思えませんが、必要に応じて作成できます。
Sumantが言ったように、多次元配列は組み込みのC配列を使用するよりもはるかに使いやすくなっていますstd::array
。
ネストstd::array
すると、非常に読みにくくなり、不必要に冗長になります。
例えば:
std::array<std::array<int, 3>, 3> arr1;
に比べ
char c_arr[3][3];
また、注目すべきことbegin()
、end()
およびsize()
すべての戻り値無意味ときの巣std::array
。
これらの理由から、私は自分の固定サイズの多次元配列のコンテナを作成し、しましたarray_2d
とarray_3d
。これらはstd::array
2次元および3次元の多次元配列に類似していますが、これらは組み込みの多次元配列よりも安全で、パフォーマンスも低下しません。珍しいので、3より大きい次元を持つ多次元配列のコンテナーは含めませんでした。C ++ 0xでは、任意の数の次元をサポートする可変テンプレートバージョンを作成できます。
2次元バリアントの例:
//Create an array 3 x 5 (Notice the extra pair of braces)
fsma::array_2d <double, 3, 5> my2darr = {{
{ 32.19, 47.29, 31.99, 19.11, 11.19},
{ 11.29, 22.49, 33.47, 17.29, 5.01 },
{ 41.97, 22.09, 9.76, 22.55, 6.22 }
}};
完全なドキュメントはここにあります:
http://fsma.googlecode.com/files/fsma.html
ここからライブラリをダウンロードできます。
arr[x][y]
場合arr
、配列の配列、ポインターの配列、配列へのポインター、またはポインターへのポインターのいずれであるかはわかりません。すべての実装は、ニーズに応じて正当です。そして、おそらく多次元配列のほとんどの実際の使用例では、実行時にサイズを決定する必要があります。
C ++で使用できるCスタイルの配列は、実際には実際のC配列ほど用途が広くありません。違いは、Cでは配列型がランタイムサイズを持つことができるということです。以下は有効なCコードですが、C ++ Cスタイルの配列でもC ++ array<>
型でも表現できません。
void foo(int bar) {
double tempArray[bar];
//Do something with the bar elements in tempArray.
}
C ++では、一時配列をヒープに割り当てる必要があります。
void foo(int bar) {
double* tempArray = new double[bar];
//Do something with the bar elements behind tempArray.
delete[] tempArray;
}
これは、コンパイル時には分からないstd::array<>
ため、では実現できませんbar
。C++のCスタイル配列またはのいずれかを使用する必要がありますstd::vector<>
。
最初の例は比較的簡単にC ++で表すことができますが(new[]
and が必要ですdelete[]
)、次のことはC ++なしでは実現できませんstd::vector<>
。
void smoothImage(int width, int height, int (*pixels)[width]) {
int (*copy)[width] = malloc(height*sizeof(*copy));
memcpy(copy, pixels, height*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y][x] = //compute smoothed value based on data around copy[y][x]
}
}
free(copy);
}
ポイントは、ライン配列へのポインターint (*)[width]
はC ++でランタイム幅を使用できないため、C ++での画像操作コードがCよりもはるかに複雑になることです。画像操作の例の典型的なC ++実装は次のようになります。
void smoothImage(int width, int height, int* pixels) {
int* copy = new int[height*width];
memcpy(copy, pixels, height*width*sizeof(*copy));
for(y = height; y--; ) {
for(x = width; x--; ) {
pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
}
}
delete[] copy;
}
このコードは、上記のCコードとまったく同じ計算を行いますが、インデックスが使用される場合は常に手動でインデックス計算を実行する必要があります。2Dの場合、これはまだ実行可能です(インデックスの計算を間違える機会がたくさんあるとしても)。ただし、3Dの場合は非常に厄介です。
C ++でコードを書くのが好きです。しかし、多次元データを操作する必要があるときはいつでも、コードのその部分をCに移動する必要があるかどうかを本当に自問しています。
gcc
たとえば)を実装するコンパイラがあります。C11はかなり興味深いものをオプションにしました、そして私はそれが彼らが機能を非合法化したいと思っているからではないと思います。私は、彼らが完全に標準に準拠したコンパイラーを作成するためのレベルを下げたいと思っている兆候であると思う傾向があります。 VLAをすぐに実装する必要がないプラットフォーム。
std::array
遅くないかもしれません。しかし、私は単純なストアを使用してベンチマークを行い、std :: arrayから読み取りました。以下のベンチマーク結果を参照してください(W8.1、VS2013 Update 4):
ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;
test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305
否定的なマークによると、私が使用したコードはペーストビンにあります(リンク)
ベンチマーククラスコードはこちらです。
ベンチマークについてはよくわかりません...コードに欠陥がある可能性があります
long test_arr_without_init() { return ARR_SIZE; }
void test_arr_without_init() {}
今に変えることができることを意味します。測定しているコードが測定したいコードであることを確認するには、実際にフープをジャンプする必要があります。
std::array
std::array
C配列よりもパフォーマンスが低下する方法を教えてください。
at()
、それはではないoperator[]
だけのような、std::vector
。パフォーマンスの低下やコードの肥大化はありません。std::array
コンパイラーはこの種のものを最適化するように設計されています。そしてもちろん、checked関数の追加は優れたデバッグツールであり、大きな利点です。@Lou Franco:すべてのC ++コードは、標準ライブラリに依存している可能性があります。@Earlz:利用可能なSTLがない場合、それはC ++ではなく、それで終わりです。
std::array
同等のC配列の使用量よりも大きくなるようにするには、ひどいコンパイラーが1つ必要です。