std :: arrayとアレイのパフォーマンス


84

次のような非常に単純な配列を作成したい場合

int myArray[3] = {1,2,3};

std::array代わりに使用する必要がありますか?

std::array<int, 3> a = {{1, 2, 3}};

std :: arrayを通常のものよりも使用する利点は何ですか?それはよりパフォーマンスが良いですか?コピー/アクセスの処理が簡単ですか?


2
std ::で多次元配列を定義するのは難しいでしょう
goGud 2015年

15
@goGud:難しくはありませんが、もっと冗長です。
マイクシーモア

1
ポインタの減衰、参照の取得など...、c配列については多くのことが奇妙です。イテレータはc配列の場合はポインタであり、for (auto i = ++std::begin(myArray); . . . コンパイルすらできない可能性があります(基本型のテンポラリは、少なくともclang 6では変更できないようです)
PatrickFromberg18年

初期化も魔法のように異なります:struct Direction { int32_t dw; int32_t dh; };そしてstatic const Direction DIRECTIONS[DIRECTIONS_COUNT] { { -1, 1}, {0,1}, {1,1} , { 1, 0 }, {1,-1}, {0,-1} , {-1,-1}, {-1,0} };コンパイルします。ただし、std::array<Direction,DIRECTIONS_COUNT>同じ初期化子リストを使用してに変更すると、突然「初期化子が多すぎます」というエラーが発生します。(言語= C ++ 17とVS 2019コミュニティ)
BitTickler

std::array初期化で二重角かっこを使用するのはなぜですか?
Marc.23 7719

回答:


101

std::array通常のものよりも使用する利点は何ですか?

フレンドリーな値セマンティクスを備えているため、値によって関数に渡したり、関数から返したりすることができます。そのインターフェースにより、サイズを見つけて、STLスタイルのイテレーターベースのアルゴリズムで使用することがより便利になります。

それはよりパフォーマンスが良いですか?

まったく同じである必要があります。定義上、これは配列を唯一のメンバーとして含む単純な集合体です。

コピー/アクセスの処理が簡単ですか?

はい。


41

Astd::arrayは、Cスタイルの配列の非常に薄いラッパーであり、基本的に次のように定義されます。

template<typename T, size_t N>
class array
{
public:
    T _data[N];
    T& operator[](size_t);
    const T& operator[](size_t) const;
    // other member functions and typedefs
};

これは集合体であり、基本的な型のように使用できます(つまり、値渡し、割り当てなどが可能ですが、標準のC配列を別の配列に直接割り当てたりコピーしたりすることはできません)。いくつかの標準実装(お気に入りのIDEから定義にジャンプするか、直接開く<array>)を確認する必要があります。これは、非常に読みやすく、理解しやすいC ++標準ライブラリの一部です。


24

std::array は、他のC ++コンテナのセマンティクスのような「通常の」値を与えるC配列のゼロオーバーヘッドラッパーとして設計されています。

追加機能を楽しんでいる間は、ランタイムパフォーマンスの違いに気付かないはずです。

C ++ 11またはブーストが手元にある場合は、スタイル配列のstd::array代わりに使用int[]することをお勧めします。


10

それはよりパフォーマンスが良いですか?

まったく同じである必要があります。定義上、これは配列を唯一のメンバーとして含む単純な集合体です。

std::array特定のプラットフォームによっては、C-arrayと比較して常に同じアセンブリコードが生成されるとは限らないため、状況はより複雑に見えます。

私はこの特定の状況をgodboltでテストしました

#include <array>
void test(double* const C, const double* const A,
          const double* const B, const size_t size) {
  for (size_t i = 0; i < size; i++) {
    //double arr[2] = {0.e0};//
    std::array<double, 2> arr = {0.e0};//different to double arr[2] for some compiler
    for (size_t j = 0; j < size; j++) {
      arr[0] += A[i] * B[j];
      arr[1] += A[j] * B[i];
    }
    C[i] += arr[0];
    C[i] += arr[1];
  }
}

GCCClangは、Cアレイバージョンとバージョンの両方で同一のアセンブリコードを生成しstd::arrayます。

ただし、MSVCICPCは、アレイのバージョンごとに異なるアセンブリコードを生成します。(私はICPC19を-Ofastとでテストしました-Os; MSVC-Ox-Os

なぜそうなるのか、私にはわかりません(std :: arrayとc-arrayの動作はまったく同じだと思います)。たぶん、採用されているさまざまな最適化戦略があります。

少しおまけとして:ICPCにはバグがあるようです。

#pragma simd 

状況によってはc-arrayを使用する場合のベクトル化用(c-arrayコードは間違った出力を生成します。std::arrayバージョンは正常に機能します)。

残念ながら、非常に複雑なコードを最適化する際にその問題を発見したため、そのための最小限の実用的な例はまだありません。

C-array /std::arrayとについて何かを誤解しただけではないと確信できる場合は、Intelにバグレポートを提出し#pragma simdます。


1
コンパイラのバグと見なすことができますか?
OznOg

8

std::array生の配列にはない値のセマンティクスがあります。これは、それをコピーstd::arrayしてプリミティブ値のように扱うことができることを意味します。関数の引数として値または参照で受け取ることができ、値で返すことができます。

をコピーしない場合std::arrayは、生の配列とパフォーマンスの違いはありません。コピーを作成する必要がある場合std::arrayは、正しいことを実行し、それでも同等のパフォーマンスを提供するはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.