C ++では、コンパイル時にサイズを決定する必要がある場合、std :: arrayのポイントは何ですか?

2020-02-15 c++ c++11 stdarray

私の無知をstd::arrayてくださいstd::arrayは通常の配列のSTLの代替物であるように思われます。ただし、配列のサイズはテンプレートパラメーターとして渡す必要があるため、実行時にのみ認識されるサイズのstd::arrayを作成できません。

std::array<char,3> nums {1,2,3}; // Works.

constexpr size_t size = 3;
std::array<char,size> nums {1,2,3}; // Works.

const buf_size = GetSize();
std::array<char, buf_size> nums; // Doesn't work.

C ++の配列の非常に重要な使用例の1つは、実行時の入力に基づいて固定サイズのデータ​​構造を作成することです(たとえば、ファイルを読み込むためのバッファーを割り当てる)。

これに使用する回避策は次のとおりです。

// Create a array pointer for on-the-spot usecases like reading from a file.
char *data = new char[size];
...
delete[] data;

または:

// Use unique_ptr as a class member and I don't want to manage the memory myself.
std::unique_ptr<char[]> myarr_ = std::unique_ptr<char[]>(new char[size]);

固定サイズを気にしない場合、次のように事前定義されたサイズでstd::vector<char>を使用できることを認識しています。

std::vector<char> my_buf (buf_size);

std::array設計者がこのユースケースを無視することを選んだのはなぜですか?たぶん、私はstd::array実際のユースケースを理解していません。

編集:私の質問を表現する別の方法もあると思います-デザイナーが、コンストラクターパラメーターとしてではなく、テンプレートパラメーターとしてサイズを渡すことを選択したのはなぜですか?後者を選択すると、 std::array現在持っている機能を提供することが難しくなりますか?私にはそれは意図的な設計選択のように思えますが、その理由はわかりません。

Answers

std::arrayは、Cスタイルの配列の代替です。

C ++標準では、コンパイル時に定義されたサイズなしでCスタイルの配列を宣言することはできません。

プログラミングのしやすさ

std::arrayは、 std::vector使用されるいくつかの有益なインターフェースとイディオムを促進します。通常のCスタイルの配列では、 .size()sizeofハックなし) .at() (範囲外の例外)、 front()/back() 、反復子などを持つことはできません。すべてを手作業でコーディングする必要があります。

多くのプログラマーは、上記のプログラミング手法を利用したいという理由だけで、サイズが既知のサイズの配列をコンパイルする場合でもstd::vector選択できます。しかし、それはコンパイル時の固定サイズの配列で利用可能なパフォーマンスを奪います。
したがって、 std::arrayは、Cスタイルの配列を思いとどまらせるためにライブラリメーカーによって提供されましたが、コンパイル時にサイズがわかっている場合はstd::vector避けます。

私が理解している2つの主な理由は次のとおりです。

  • std::array 、collection-typesのSTLインターフェースを実装し、 std::arrayをSTLイテレータを受け入れる関数およびメソッドにそのまま渡すことができます。
  • 配列ポインターの減衰を防ぐには...(以下)

...これは、 Array Pointer Decayを防ぐため、関数/メソッドの境界を越えて型情報を保持します。

裸のC / C ++配列を指定すると、次の4つの方法で、パラメーター引数として別の関数に渡すことができます。

void by_value1   ( const T* array )
void by_value2   ( const T array[] )
void by_pointer  ( const T (*array)[U] )
void by_reference( const T (&array)[U] )
  • by_value1by_value2受信機能がわからないため、両方の意味的に同じと原因ポインタの崩壊ですsizeof配列。
  • by_pointerby_referenceどちらも、既知のコンパイル時定数によるU必要としますが、 sizeof情報を保持します。

したがって、 by_pointerまたはby_referenceを使用して配列の減衰を回避する場合、配列のサイズを変更するたびにメンテナンスの問題が発生するため、 Uそのサイズのすべての呼び出しサイトを手動で更新する必要があります。

std::arrayを使用することで、 Uがパラメーターである関数をtemplate関数にすることで処理されます(許可されているため、 by_pointerおよびby_referenceテクニックを使用できますが、よりby_pointer構文を使用できます)。

...だからstd::array は5番目の方法を追加します

template<typename T, size_t N>
void by_stdarray( const std::array<T,N>& array )

Related