web-dev-qa-db-ja.com

vector :: resize()とvector :: reserve()の選択

vectorメンバー変数にメモリを事前に割り当てています。以下のコードは最小限の部分です

class A {
  vector<string> t_Names;
public:
  A () : t_Names(1000) {}
};

ある時点で、t_Names.size()1000と等しい場合。 100だけサイズを増やすつもりです。その後、1100に達すると、再び100ずつ増加します。

私の質問は、vector::resize()vector::reserve()のどちらを選択するかです。この種のシナリオにはより良い選択肢がありますか?

編集t_Namesの正確な見積もりがあります。私はそれが700から800前後であると推定します。ただし、certain(めったにない)状況では、1000より大きくなる可能性があります。

133
iammilind

2つの機能は大きく異なることを行います!

resize() メソッド(および引数をコンストラクターに渡すことは、それと同等です)は、適切な数の要素をベクターに挿入または削除して、サイズを指定します(値を指定するオプションの2番目の引数があります)。それはsize()に影響を与え、反復はそれらすべての要素を調べ、Push_backはそれらの後に挿入し、operator[]を使用してそれらに直接アクセスできます。

reserve() メソッドはメモリのみを割り当てますが、初期化されないままにします。 capacity()にのみ影響しますが、size()は変更されません。ベクトルには何も追加されないため、オブジェクトの値はありません。その後、要素を挿入すると、再割り当ては行われません。事前に行われたためです。しかし、それが唯一の効果です。

だからあなたが望むものに依存します。 1000個のデフォルト項目の配列が必要な場合は、resize()を使用します。 1000個のアイテムを挿入する予定の配列が必要で、いくつかの割り当てを避けたい場合は、reserve()を使用します。

EDIT:Blastfurnaceのコメントで質問をもう一度読んで、あなたの場合は正しい答えはdon ' t preallocate手動で。必要に応じて、最後に要素を挿入し続けるだけです。ベクトルは必要に応じて自動的に再割り当てし、前述の手動の方法よりも効率的により多く実行します。 reserve()が理にかなっている唯一のケースは、事前に簡単に入手できる必要がある合計サイズの合理的に正確な見積もりがある場合です。

EDIT2:広告の質問の編集:最初の見積もりがある場合は、reserve()その見積もり。それが十分でないことが判明した場合は、ベクターにそれをさせてください。

229
Jan Hudec

resize()はメモリを割り当てるだけでなく、creates引数としてresize()に渡すdesiredサイズと同じ数のインスタンスを割り当てます。ただし、reserve()はメモリを割り当てるだけで、インスタンスは作成しません。あれは、

std::vector<int> v1;
v1.resize(1000); //allocation + instance creation
cout <<(v1.size() == 1000)<< endl;   //prints 1
cout <<(v1.capacity()==1000)<< endl; //prints 1

std::vector<int> v2;
v2.reserve(1000); //only allocation
cout <<(v2.size() == 1000)<< endl;   //prints 0
cout <<(v2.capacity()==1000)<< endl; //prints 1

出力( オンラインデモ ):

1
1
0
1

したがって、デフォルトで作成されたオブジェクトが必要ない場合は、resize()は望ましくない場合があります。同様に遅くなります。さらに、Push_back()の新しい要素を追加すると、ベクトルのsize()がさらに増加し​​ます新しいメモリを割り当てる(既存の要素を新しく割り当てられたメモリスペースに移動することも意味します)。すでに十分なメモリが割り当てられていることを確認するために開始時にreserve()を使用している場合、ベクトルのsize()Push_back()に増加すると増加しますが、実行されるまで新しいメモリは再び割り当てられません予約したスペースのうち

26
Nawaz

予約時にオブジェクトを初期化しない場合は予約します。また、サイズを変更するときに、カウントと使用カウントを論理的に区別して追跡することもできます。そのため、インターフェースには動作の違いがあります。ベクトルは予約時に同じ数の要素を表し、シナリオでサイズを変更すると100要素大きくなります。

この種のシナリオには他に良い選択肢はありますか?

デフォルトの動作と戦うときの目的に完全に依存します。カスタマイズされたアロケーターを好む人もいますが、あなたのプログラムで何を解決しようとしているかをよりよく知る必要があります。

fwiw、多くのベクトル実装は、成長する必要があるときに割り当てられた要素数を単純に2倍にします-ピーク割り当てサイズを最小限にしようとしていますか、またはロックフリープログラムなどのために十分なスペースを確保しようとしていますか?

2
justin

説明から、ベクトルt_Namesの割り当てられた記憶領域を「予約」したいようです。

resizeは、reserveが割り当てただけで構成しない、新しく割り当てられたベクトルを初期化することに注意してください。したがって、 'reserve'は 'resize'よりもはるかに高速です

resizereserve の違いに関するドキュメントを参照できます。

1
dip