これでstd :: arrayができたので、Cスタイルの配列にはどのような使用法が残っていますか?


回答:


60

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

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

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

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


7
長さを指定せずに配列を作成する可変関数テンプレートを作成できます。
2015

2
C ++ 17クラステンプレートの控除では、初期化子の数の自動控除がサポートされています。たとえば、「auto a = std :: array {1、2、3};」のようになります。
Ricky65

Nitpick:文字列リテラルのタイプはconst char[]
Bulletmagnet

30

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

もちろん、を実装するにはC配列が必要ですがstd::array、ユーザーがC配列を必要とする理由はそれだけではありません。加えて、NO、std::arrayCアレイ未満パフォーマンスはない、の境界確認済みアクセスのためのオプションを有します。そして最後に、どのC ++プログラムも標準ライブラリに依存することは完全に合理的です-それが標準であるということの一種です-標準ライブラリにアクセスできない場合、コンパイラは非準拠であり、質問は「C ++」ではなく「C ++」とタグ付けされています。「C ++とは、不適切だと感じたために仕様の半分を逃したもの」ではありません。


1
うーん。別の言語から呼び出され、パラメーターとして何かを渡す必要があるC ++コードを作成している場合はどうなりますか?
asveikau

3
自立型の実装では、ほとんどすべての標準ライブラリを省略しても、引き続き準拠できます。std::arrayしかし、独立したC ++ 11実装に実装できないコンパイラーについては、深刻な疑いがあります。
Dennis Zickefoose

11
C ++ 0x最終ドラフト(ドキュメントN3092)§1.4.7 "ホストされた実装と独立型の2種類の実装が定義されています。ホストされた実装の場合、この国際標準は利用可能なライブラリのセットを定義します。オペレーティングシステムの利点なしに実行され、特定の言語サポートライブラリを含む実装定義のライブラリセットがあります
。STL

24

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


1
ただし、array次元を失うことなく多次元を関数に渡すことができます。そして、それを関数テンプレートに渡すと、その関数は、次元と各次元のサイズの両方、またはそれらの2つのうちの1つだけを推定できます。これは、主に任意の次元で機能する科学テンプレートライブラリにとって興味深いかもしれません。
セバスチャンマッハ

29
シンプルは、template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;これらの問題のいずれかを解決する必要があります。
Miles Rout 2013年

6
あなたの例c_arrはコピーするのに非常に高価です!そのためには、自分でコードを提供する必要があります。減衰するポインタは、コピーよりも参照に近いものであり、それが必要なstd::array場合は、参照を渡すために使用できます。
ChetS 2014年

1
@MilesRoutは技術的にはstd::size_t代わりにすべきではありませんintか?つまらないことを申し訳ありませんが、これはそれを普遍的にするでしょう。
ロビー

1
@ robbie0630 size_t40億行以上の行または列を持つ配列が必要となるシナリオがたくさんあるとは思えませんが、必要に応じて作成できます。
Miles Rout

13

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_2darray_3d。これらはstd::array2次元および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


4
固定サイズのCスタイルの配列は簡単ですが、次元を変えたい場合は複雑になります。たとえば、が与えられたarr[x][y]場合arr、配列の配列、ポインターの配列、配列へのポインター、またはポインターへのポインターのいずれであるかはわかりません。すべての実装は、ニーズに応じて正当です。そして、おそらく多次元配列のほとんどの実際の使用例では、実行時にサイズを決定する必要があります。
キーストンプソン

n次元配列のその可変のテンプレート実装を見てみたいです!最高のメタプログラミング!
steffen 2014年

3
@steffen私は数年前に試みました。あなたはそれをここで見ることができます:code.google.com/p/fsma/source/browse/trunk/…。ここでテストケース:code.google.com/p/fsma/source/browse/trunk/…。私はそれがもっとよくできると確信しています。
Ricky65、2014年

5

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に移動する必要があるかどうかを本当に自問しています。


7
少なくともClangとGCCはC ++でVLAをサポートしていることに注意してください。
Janus Troelsen、2014

@JanusTroelsenと、サポートする要素タイプがひどく制限されていること。
2015

C11はVLAをオプションにしませんか?もしそうなら、私はあなたの答えは誤解を招くと思います。C99が標準でC11が標準ではなかった場合、それは正しいでしょう。
Zボソン2016年

1
@Zboson C99はC標準であり、そのVLA機能(gccたとえば)を実装するコンパイラがあります。C11はかなり興味深いものをオプションにしました、そして私はそれが彼らが機能を非合法化したいと思っているからではないと思います。私は、彼らが完全に標準に準拠したコンパイラーを作成するためのレベルを下げたいと思っている兆候であると思う傾向があります。 VLAをすぐに実装する必要がないプラットフォーム。
cmaster-2016年

-1

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

否定的なマークによると、私が使用したコードはペーストビンにあります(リンク

ベンチマーククラスコードはこちらです。

ベンチマークについてはよくわかりません...コードに欠陥がある可能性があります


6
ベンチマークコードまたはコンパイルフラグなしのベンチマーク結果?さあ、あなたはもっと上手にできる。
R.マルティーニョフェルナンデス

FWIW、ほんのわずかなコードがすでにベンチマークに深刻な欠陥があることを示しています。十分に賢いコンパイラは、すべてをそのままにしてくれますlong test_arr_without_init() { return ARR_SIZE; }
R. Martinho Fernandes

それはほんの一例です。大したことではないと思った。/ O2 / Ot / Glを使用して、VS 2013でリリースビルドを使用してvoidを返すようにコードを変更しました。
K'Prime 2015

戻り値を削除することは、コンパイラがすべてをvoid test_arr_without_init() {}今に変えることができることを意味します。測定しているコードが測定したいコードであることを確認するには、実際にフープをジャンプする必要があります。
R.マルティーニョフェルナンデス

-6
  1. のようなものを実装する std::array
  2. STLを使用したくない場合、または使用できない場合
  3. パフォーマンスのために

27
std::arrayC配列よりもパフォーマンスが低下する方法を教えてください。
Xeo

2
ウィキペディアから:「配列の実装は、境界チェックを行う必要はありません。ただし、boostの実装は、operator []に対しては行いますが、イテレータに対しては行いません。」-したがって、operator []は低速です。私は実装を見ていませんが、実装内のコードはオプティマイザの邪魔になる可能性があります。
ルーフランコ、

19
@Aaron McDaid:だけでだat()、それはではないoperator[]だけのような、std::vector。パフォーマンスの低下やコードの肥大化はありません。std::arrayコンパイラーはこの種のものを最適化するように設計されています。そしてもちろん、checked関数の追加は優れたデバッグツールであり、大きな利点です。@Lou Franco:すべてのC ++コードは、標準ライブラリに依存している可能性があります。@Earlz:利用可能なSTLがない場合、それはC ++ではなく、それで終わりです。
パピー

6
@Earlz:C ++標準には標準ライブラリが含まれています。ライブラリを使用できない場合、ライブラリは適合しません。第二に、std::array同等のC配列の使用量よりも大きくなるようにするには、ひどいコンパイラーが1つ必要です。
パピー

5
@Earlz:「完全に準拠していない」と「仕様が何百ページもある機能がない」との間には大きな違いがあります。
パピー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.