私は、ベクターが内部的にどのように働くのか誤解していると思います。
ベクトル典型的に格納するだけの内部3のもの(すなわち、スタック上にある):
- そのサイズ
- 能力(すなわち、それがサイズ変更せずに成長することができた最大のサイズまでです)
- 実際のデータ
を格納するヒープ上の配列へのポインタは、(多くの場合、パフォーマンス上の理由のために、実装が代わりに3つのポインタを使用するが、概念的には同じです)。
これは、拡大または縮小可能な部分がヒープに格納されていることを意味します。 push_back
要素をvexample[1]
にすると、サイズが大きくなり、必要に応じてサイズ、容量、ポインタの値が更新されますが、スタックにさらにスペースが必要というわけではありません。ここで、「固定」とはコンパイル時に決定されることを意味します。私たちはsize
とcapacity
がint
として実装され、それぞれ4つのバイトを必要とし、ポインタが8つのバイトを必要としていることを前提とした場合
、あなたはベクトルは関係なく、スタック上の4 + 4 + 8 = 16バイトが必要であることを持っていますそれに含まれる要素のタイプと数、ヒープ上のcapacity * sizeof(T)
バイトです。使用されているヒープ上のメモリ量は変わる可能性がありますが、スタック上のメモリ量は変化しません。
あなたのケースでは、vexample
の要素はやはりベクトルであるため、それぞれ16バイトと割り当てられた容量のサイズを必要とします。したがって、メモリのレイアウトは次のようになります。
vexample
はスタック上で16バイト必要です。これらの16バイトのうち、8はヒープの領域へのポインタであり、2つの要素の配列があり、それぞれ16バイトを必要とするため、32バイトの連続ブロックです。最初の16はvexample[0]
、最後の16 vexample[1]
です。それぞれにはint
の配列へのポインタが含まれています。
ヒープ上のデータが再配置される必要があるかもしれませんが、これは他のものを "押しのける"ことはありません。同じベクトルの要素を連続して格納する必要がありますが、 異なるベクトルに対応するメモリの領域はそのような要件を持っていません。したがって、push_back
要素をvexample[1]
にして強制的に成長させると、vexample[0]
でもvexample
でもvexample[2]
(存在する場合)も何もする必要はありません。特にvexample[2]
は、vexample[1]
が成長するので移動する必要はありません。逆に、vexample[1]
が大きくなると、vexample[1]
は新しい場所を見つける必要があります。
ベクトルの可変サイズの部分がスタックに保存されていて、すべてが互いに隣に格納されている場合、これはすべて問題になります。しかし、これはまさにヒープへのポインタを格納するだけの理由であり、そこではすべての肥大や縮小が起こり、害を及ぼすことはありません。
'vexample [2]'は、範囲外のアクセスであるため、未定義の動作があります。 –
'vexample'はアドレスの配列です - 各スロットは固定サイズです。より低いインデックスエントリの1つに 'push_back 'すると、配列内のエントリはメモリ内を移動しません。むしろ、定義されたアドレスのメモリ位置に移動し、_that_のサイズを変更します。 –
@Kerrek SB申し訳ありません、それはタイプ – Jeff