web-dev-qa-db-ja.com

これでstd :: arrayができたので、Cスタイルの配列には何が残っていますか?

_std::array_は、C配列よりもはるかに優れています。レガシーコードと相互運用したい場合でも、std::array::data()を使用できます。古い学校のアレイが必要になる理由はありますか?

85

何かを見逃していない限り(標準の最新の変更にあまり従わなかったため)、Cスタイルの配列の使用のほとんどは依然として残っています。 std::arrayは静的な初期化を許可しますが、初期化子はまだカウントしません。 std::arrayの前のCスタイル配列の唯一の実際の使用は、次の行に沿って静的に初期化されたテーブルのためでした。

MyStruct const table[] =
{
    { something1, otherthing1 },
    //  ...
};

通常のbeginおよびendテンプレート関数(C++ 11で採用)を使用してそれらを反復処理します。コンパイラが初期化子の数から決定するサイズについては言及していません。

編集:私が忘れていたもう一つ:文字列リテラルはまだCスタイルの配列です。つまり、タイプchar[]を使用します。 std::arrayがあるからといって、文字列リテラルの使用を除外する人はいないと思います。

59
James Kanze

いいえ、ええと、率直に言って。そして、30文字で。

もちろん、std::arrayを実装するにはC配列が必要ですが、それがユーザーがC配列を必要とする理由ではありません。さらに、いいえ、std::arrayはC配列よりパフォーマンスが劣りません。andには、境界チェックアクセスのオプションがあります。そして最後に、C++プログラムが標準ライブラリに依存することは完全に合理的です(標準であるという点です)。標準ライブラリにアクセスできない場合、コンパイラは非準拠であり、質問は「C++」ではなく「C++」とタグ付けされます。C++と、C++以外のものは不適切だと感じたために仕様の半分を逃してしまいます。

29
Puppy

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]はコピーに非常にコストがかかります。

25
Sumant

Sumantが言ったように、多次元配列は_std::array_よりも組み込みC配列を使用する方がはるかに簡単です。

ネストすると、_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

ここからライブラリをダウンロードできます。

http://fsma.googlecode.com/files/fsma.Zip

13
Ricky65

C++で利用可能なCスタイルの配列は、実際のC配列よりも実際にはあまり用途がありません。違いは、Cでは、配列型にruntimeサイズを指定できることです。以下は有効な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;
}
_

barはコンパイル時には不明であり、C++のCスタイル配列または_std::array<>_を使用する必要があるため、これは_std::vector<>_では実現できません。


最初の例はC++で比較的簡単に表現できますが(_new[]_および_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に移動するべきかどうかを自問します。

5
cmaster