2017-02-08 3 views
0

のは、私はこのようなプログラムがあるとしましょう:最初の行で内部的に、ベクトルのベクトルはどのように拡張されますか? C++

#include<vector> 

int main() 
{ 
    std::vector< std::vector <int> > vexample(2); 
    vexample[1].push_back(0); 
    vexample[0].push_back(0); 
} 

を、私はint型の2長さゼロのベクトルを含むベクトルを初期化します。 2行目で、intを2番目のベクトルにpush_back()し、vexample [1]のサイズを変更します。

pushback()によって最初のvexample [0]のサイズが変更されたときの次の行のvexampleは、ベクトルのベクトルですか? vexample [2]は4バイト前に移動しましたか?

+0

'vexample [2]'は、範囲外のアクセスであるため、未定義の動作があります。 –

+0

'vexample'はアドレスの配列です - 各スロットは固定サイズです。より低いインデックスエントリの1つに 'push_back 'すると、配列内のエントリはメモリ内を移動しません。むしろ、定義されたアドレスのメモリ位置に移動し、_that_のサイズを変更します。 –

+0

@Kerrek SB申し訳ありません、それはタイプ – Jeff

答えて

2

私は、ベクターが内部的にどのように働くのか誤解していると思います。

ベクトル典型的に格納するだけの内部3のもの(すなわち、スタック上にある):

  • そのサイズ
  • 能力(すなわち、それがサイズ変更せずに成長することができた最大のサイズまでです)
  • 実際のデータ

を格納するヒープ上の配列へのポインタは、(多くの場合、パフォーマンス上の理由のために、実装が代わりに3つのポインタを使用するが、概念的には同じです)。

これは、拡大または縮小可能な部分がヒープに格納されていることを意味します。 push_back要素をvexample[1]にすると、サイズが大きくなり、必要に応じてサイズ、容量、ポインタの値が更新されますが、スタックにさらにスペースが必要というわけではありません。ここで、「固定」とはコンパイル時に決定されることを意味します。私たちはsizecapacityintとして実装され、それぞれ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]は新しい場所を見つける必要があります。

ベクトルの可変サイズの部分がスタックに保存されていて、すべてが互いに隣に格納されている場合、これはすべて問題になります。しかし、これはまさにヒープへのポインタを格納するだけの理由であり、そこではすべての肥大や縮小が起こり、害を及ぼすことはありません。

+0

"です。それで、ベクトルには、それに含まれる要素のタイプと数に関係なく、スタックに4 + 4 + 8 = 16バイトが必要で、容量* sizeof(T)バイトヒープ上に。 - どちらの言葉も真実ではない。実際にはそうではない可能性が高いです。スタックとヒープに関するあなたの記述は、かなり間違っていて誤解を招きます。 –

+0

@CrazyEddie:理由を教えていただけますか?彼らはどちらも私にとって正しいようです。 –

+0

まず、ベクトルが必要とするメモリの量をそのように計算することはできません。 'sizeof(vector )'は、それが構成する型がそれに加算されたとしても必ずしも16ではありません。第二に、そのストレージに割り当てられたメモリは必ずしも 'sizeof(T)* capacity()'であるとは限りません。 OSはそれを担当しており、それほど多くを割り当てることはほとんどありません。最後に、ベクトル内の変数がスタックに割り当てられているかどうかは言えません。また、Tの配列に割り当てられた領域はヒープ上にないかもしれません。 –

2

各ベクトルには、アイテムを保持するためにフリーストアに割り当てられたメモリへのポインタが含まれています。だから、全く何も起こらないvexamplevexample[0]がポインタを再装着する可能性があるデータは、vexample[1]のままです。 vexample要素のいずれも大きくも小さくもなりません。

関連する問題