読者です 読者をやめる 読者になる 読者になる

ぷろみん

プログラミング的な内容を扱ってます

生配列よりもstd::arrayを使った方が良い理由

概要

生配列を使う人がstd::arrayを使うきっかけになれば良いなと思います。

パフォーマンス

最適化をかければstd::arrayは生配列と全く同じアセンブリを吐き出す事が知られています。
つまり、パフォーマンスに差はありません。

アルゴリズム

アルゴリズムに関しては生配列にも適応できるので問題無いでしょう。

std::array<int, 10> a;
std::fill(a.begin(), a.end(), 10);

int b[10];
std::fill(std::begin(b), std::end(b), 10);

forのイテレーション

イテレーションに関してはどれも割と難有りですね。
range based forが圧倒的にシンプルです。

生配列のサイズを取得するのにtemplate関数を作らなければいけないのが面倒です。
マクロは個人的にはやめた方が良いと思います。

std::array<int, 10> a;
for(auto i = a.begin(), end = a.end(); i != end; ++i){}
for(auto i = a.rbegin(), end = a.rend(); i != end; ++i){}
for(std::size_t i = 0, size = a.size(); i < size; ++i){}
for(auto item: a){}

// auto Size(const T (&)[size]){ return size; }
int b[10];
for(int* i = b; i != b + Size(b); ++i){}
for(int* i = b + Size(b) - 1; i != b ; --i){}
for(int i = 0; i < Size(b); ++i){}
for(auto item: b){}

範囲外アクセスのチェック

流石にこれはstd::arrayの方が楽ですね。(なのにみんなatはあまり使わない)
範囲外アクセスがひっそりと行われるの怖くないんでしょうか。

std::array<int, 10> a;
a.at(5);

auto input = 5;
int b[10];
if(input < 0 || Size(b) <= input){
    throw std::out_of_range("faild");
}

可搬性

今でこそマシに書けますが、生配列の参照型の戻り値は一旦typedefかusingで定義してからじゃないと書けませんでした。
ポインタで扱うのはナンセンスです。サイズ分からなくなっちゃいますから。

auto Foo(std::array<int, 10> a){ return a; }
auto Bar(int (&a)[10]){ return a; }

入れ替えも両方以下でいけます。

std::swap(a, b);

しかし、代入できるのはarrayだけです。

std::array<int, 10> a;
a = Foo(a);
int b[10];
// エラー
//b = Bar(b);

比較

std::array<int, 10> a, aa;
if(a == aa){}

int b[10], bb[10];
if(std::equal(std::begin(b), std::end(b), std::begin(bb))){}

まとめ

生配列でも最新の書き方したらそれなりに良い感じで書ける。でもそんな苦労するくらいならstd::array使った方が楽だと思います。