web-dev-qa-db-ja.com

なぜ配列の次元はその型の一部なのですか?

C++入門書を読んでいるときに、「配列内の要素の数は配列の型の一部です。」という文に出くわしました。だから私は次のコードを使用して調べたいと思いました:

#include<iostream>

int main()
{
    char Array1[]{'H', 'e', 'l', 'p'};
    char Array2[]{'P', 'l', 'e', 'a', 's', 'e'};

    std::cout<<typeid(Array1).name()<<std::endl;        //prints  A4_c
    std::cout<<typeid(Array2).name()<<std::endl;        //prints  A6_c

    return 0;
}

そして興味深いことに、2つの配列に対するtypeidの結果は、なんらかの違いがあることを示しています。

  • 舞台裏で何が起こっているのですか?
  • 配列のサイズを含む型を持つ必要があるのはなぜですか?サイズを変えてはいけないというだけのことですか?
  • これは配列の比較にどのように影響しますか?

コンセプトを深く理解したいだけ。

14
octopus

舞台裏で何が起こっているのですか?

動的に割り当てられないものは、定義上、同種の要素のfixed-sizeコンテナです。タイプNT要素の配列は、タイプNTオブジェクトの連続したシーケンスとしてメモリに配置されます。


配列のサイズを含む型が配列に必要なのはなぜですか?

配列の型にそのサイズを含めることが「必要」であるとは思いません。実際、ポインタを使用してTオブジェクトの連続したシーケンスを参照できます。このようなポインタは、配列に関するサイズ情報を失います。

ただし、これは便利です。これは、タイプセーフを改善し、複数の方法で使用できるコンパイル時に有用な情報をエンコードします。例として、references-to-arraysを使用して、異なるサイズの配列にオーバーロードできます

void foo(int(&array)[4]) { /* ... */ }
void foo(int(&array)[8]) { /* ... */ }

または、定数式として配列のサイズを把握する

template <typename T, std::size_t N>
constexpr auto sizeOf(const T(&array)[N]) { return N; }

これは配列の比較にどのように影響しますか?

そうではありません。

2つの数値を比較するのと同じ方法でCスタイルの配列を比較することはできません(例:intオブジェクト)。ある種の辞書式比較を記述し、さまざまなサイズのコレクションに対してそれが何を意味するかを決定する必要があります。 std::vector<T>は、 を提供し、同じロジックを配列に適用できます。


ボーナス:C++ 11以降では std::array は、コンテナのようなインターフェースを持つCスタイルの配列のラッパーです。他のコンテナとの整合性が高いため、Cスタイルの配列よりも推奨されます(例:std::vector<T>)、および 辞書編集的比較 をそのままサポートします。

20
Vittorio Romeo

作成時にオブジェクトに割り当てられるスペースの量は、そのタイプに完全に依存します。私が話している割り当ては、newまたはmallocからの割り当てではありませんが、コンストラクターを実行してオブジェクトを初期化できるように割り当てられているスペースです。

(たとえば)として定義された構造体がある場合

struct A { char a, b; }; //sizeof(A) == 2, ie an A needs 2 bytes of space

次に、オブジェクトを作成するとき:

A a{'a', 'b'};

オブジェクトを構築するプロセスをプロセスと考えることができます:

  • 2バイトのスペースを割り当てます(スタック上ですが、この例では重要ではありません)。
  • オブジェクトのコンストラクターを実行します(この場合、'a'および'b'をオブジェクトにコピーします)

必要な2バイトのスペースは、オブジェクトのタイプによって完全に決定されることに注意してください。関数への引数は重要ではありません。したがって、配列の場合、プロセスは同じですが、必要なスペースの量は配列内の要素の数によって異なります。

char a[] = {'a'}; //need space for 1 element
char b[] = {'a', 'b', 'c', 'd', 'e'}; //need space for 5 elements

したがって、abのタイプは、aには1文字分のスペースが必要であり、bには5文字分のスペースが必要であることを反映している必要があります。つまり、これらの配列のサイズは突然変更できません。5要素の配列が作成されると、常に5要素の配列になります。サイズが変化する可能性のある「配列」のようなオブジェクトを作成するには、動的メモリ割り当てが必要です。これは、本をある時点でカバーする必要があります。

8
SirGuy

これは、ランタイムライブラリの内部的な理由によるものです。たとえば、次のステートメントを検討するとします。

unsigned int i;
unsigned int *iPtr;
unsigned int *iPtrArr[2];
unsigned int **iPtrHandle;

次に、何が問題なのかが明らかになります。たとえば、unsigned int *のアドレス指定は、sizeof operatorまたはunsigned intのアドレス指定に関係する必要があります。

ここに表示される残りの部分についてはより詳細な説明がありますが、それは主にCプログラミング言語、第2版でカバーされた内容を要約したものです。宣言された型文字列のプレーン言語テキスト。

0
C. R. Ward