web-dev-qa-db-ja.com

C ++ 11でサイズがゼロのstd :: arrayの理由はありますか?

次のコードについて考えてみます。これは、C++ 11コンパイラで完全に受け入れられます。

_#include <array>
#include <iostream>

auto main() -> int {
  std::array<double, 0> A;

  for(auto i : A) std::cout << i << std::endl;

  return 0;
}
_

標準§23.3.2.8[ゼロサイズの配列]によると:

_1_配列は、特殊なケース_N == 0_のサポートを提供するものとします。

_2_ _N == 0_の場合、begin() == end() ==一意の値。の戻り値
data()は指定されていません。

_3_サイズがゼロの配列に対してfront()またはback()を呼び出す効果は定義されていません。

_4_メンバー関数swap()には、noexcept(true)と同等のnoexcept仕様が必要です。

上に表示されているように、ゼロサイズの_std::array_ sはC++ 11で完全に許可されますが、ゼロサイズの配列(例:_int A[0];_)は明示的に禁止されていますが、一部のコンパイラーでは許可されています(例: 、GCC)未定義の振る舞いのコストで。

この「矛盾」を考慮して、私は次の質問があります。

  • C++委員会がゼロサイズの_std::array_ sを許可することを決定したのはなぜですか?

  • 価値のある用途はありますか?

41
101010

汎用関数がある場合、その関数が特別なパラメーターのためにランダムに壊れてしまうのは悪いことです。たとえば、N個のランダムな要素をベクトルから受け取るテンプレート関数を作成できるとします。

template<typename T, size_t N>
std::array<T, N> choose(const std::vector<T> &v) {
   ...
}

何らかの理由でNがゼロであることが判明した場合に、これが未定義の動作またはコンパイラエラーを引き起こす場合、何も得られません。

生の配列の場合、制限の背後にある理由は、sizeof T == 0の型が必要ないことです。これにより、ポインター演算と組み合わせて奇妙な効果が発生します。特別なルールを追加しない場合、要素がゼロの配列のサイズはゼロになります。

ただし、std::array<>はクラスであり、クラスのサイズは常に> 0です。したがって、std::array<>でこれらの問題が発生することはなく、テンプレートパラメータの任意の制限のない一貫したインターフェイスが望ましいです。

43
sth

私が考えることができる1つの用途は、長さがゼロの配列の戻りが可能であり、特にチェックする機能があることです。

たとえば、_std::array_関数empty()に関するドキュメントを参照してください。次の戻り値があります。

_true if the array size is 0, false otherwise.
_

http://www.cplusplus.com/reference/array/array/empty/

長さ0の配列を返し、チェックする機能は、stlタイプの他の実装の標準に沿っていると思います。ベクトルとマップ、したがって便利です。

4

実際、これを実行できるようにしたい場合はかなりあります。他の多くの言語にも存在します。たとえば、Javaには実際にはCollections.emptyList()があり、サイズがゼロであるだけでなく、拡張、サイズ変更、または変更できないリストを返します。

使用例としては、バスを表すクラスとそのクラス内の乗客のリストがある場合があります。リストは遅延初期化される可能性があり、乗客が搭乗したときにのみ作成されます。ただし、誰かがgetPassengers()を呼び出すと、空を報告するためだけに毎回新しいリストを作成するのではなく、空のリストを返すことができます。

Nullを返すことは、クラスの内部効率にも役立ちますが、getPassengers()を呼び出すたびに結果をnullチェックする必要があるため、クラスを使用するすべての人の生活がはるかに複雑になります。代わりに、空のリストを取得した場合、コードがリストが空でないことを前提としない限り、nullであることを処理するための特別なコードは必要ありません。

1
Tim B

他のコンテナクラスと同様に、物事の配列を表すオブジェクトを作成し、その配列を空にしたり空にしたりできると便利です。それが不可能な場合は、その状態を合法的に表すために、別のオブジェクトまたは管理クラスを作成する必要があります。その機能がすでにすべてのコンテナクラスに含まれていると、非常に役立ちます。それを使用する際には、空の可能性があるコンテナとして配列を関連付け、何も指していない可能性がある場合にそのメンバーを参照する前にサイズまたはインデックスをチェックする習慣を身に付ける必要があります。

1
Dronz