デフォルトのコンストラクタを使用して作成される_std::vector
_のcapacity()
とは何ですか? size()
がゼロであることを知っています。デフォルトで構築されたベクターはヒープメモリ割り当てを呼び出さないと言えますか?
この方法では、std::vector<int> iv; iv.reserve(2345);
のような単一の割り当てを使用して、任意の予約で配列を作成することができます。何らかの理由で、2345でsize()
を開始したくないとしましょう。
たとえば、Linux(g ++ 4.4.5、カーネル2.6.32 AMD64)の場合
_#include <iostream>
#include <vector>
int main()
{
using namespace std;
cout << vector<int>().capacity() << "," << vector<int>(10).capacity() << endl;
return 0;
}
_
印刷_0,10
_。それはルールですか、それともSTLベンダーに依存していますか?
標準では、コンテナの最初のcapacity
が何であるかが指定されていないため、実装に依存しています。一般的な実装では容量がゼロから始まりますが、保証はありません。一方、std::vector<int> iv; iv.reserve(2345);
の戦略を改善する方法はありません。
Std :: vectorのストレージ実装は大きく異なりますが、私が遭遇したものはすべて0から始まります。
次のコード:
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector<int> normal;
cout << normal.capacity() << endl;
for (unsigned int loop = 0; loop != 10; ++loop)
{
normal.Push_back(1);
cout << normal.capacity() << endl;
}
std::cin.get();
return 0;
}
次の出力を提供します。
0
1
2
4
4
8
8
8
8
16
16
gCC 5.1および次の場合:
0
1
2
3
4
6
6
9
9
9
13
mSVC 2013で。
標準を理解している限り(実際には参照に名前を付けることはできませんでしたが)、コンテナのインスタンス化とメモリ割り当ては、正当な理由で意図的に切り離されています。そのため、個別の個別の呼び出しがあります
constructor
はコンテナ自体を作成しますreserve()
は、適切な大きさのメモリブロックを事前に割り当てて、指定された数のオブジェクトを少なくとも(!)収容します。そして、これは非常に理にかなっています。 reserve()
に存在する唯一の権利は、ベクトルを成長させるときに、おそらく高価な再割り当てをコード化する機会を与えることです。有用であるためには、保存するオブジェクトの数を知っているか、少なくとも経験に基づいた推測ができる必要があります。これが与えられていない場合は、無駄なメモリの再割り当てを変更するだけなので、reserve()
に近づかないほうがよいでしょう。
したがって、すべてをまとめると:
reserve()
を個別に呼び出す必要があり、これは同じ構築場所である必要はありません宿泊)reserve()
の意図されたジョブを妨げるでしょうか?Push_back()
で特定のブロックを割り当てて実装することです-reserve()
によって以前に明示的に割り当てられていない場合。これはすべて、割り当てコンストラクタによって妨げられない場合にのみ、完全な操作と利点になります。 reserve()
(およびshrink_to_fit()
)によって要求に応じてオーバーライドできる一般的なシナリオの合理的なデフォルトがあります。そのため、標準が明示的にそう述べていない場合でも、新しく構築されたベクトルが事前に割り当てられないことは、現在のすべての実装にとって非常に安全な賭けであると確信しています。
他の回答へのわずかな追加として、Visual Studioでデバッグ条件下で実行すると、容量がゼロから始まっても、デフォルトで構築されたベクターがヒープに割り当てられることがわかりました。
具体的には、_ITERATOR_DEBUG_LEVEL!= 0の場合、vectorはイテレーターのチェックに役立つスペースを割り当てます。
https://docs.Microsoft.com/en-gb/cpp/standard-library/iterator-debug-level
当時はカスタムアロケーターを使用していましたが、余分な割り当てを期待していなかったため、これは少し面倒です。
標準では容量の初期値は指定されていませんが、最大サイズを超えない限り、STLコンテナーは自動的に大きくなり、入力したデータに対応します(max_sizeメンバー関数を使用してください)。ベクトルと文字列の場合、より多くのスペースが必要になるたびにreallocによって成長が処理されます。値1〜1000を保持するベクトルを作成するとします。予約を使用しない場合、コードは通常、次のループ中に2〜18の再割り当てになります。
vector<int> v;
for ( int i = 1; i <= 1000; i++) v.Push_back(i);
予約を使用するようにコードを変更すると、ループ中に割り当てが0になる場合があります。
vector<int> v;
v.reserve(1000);
for ( int i = 1; i <= 1000; i++) v.Push_back(i);
おおまかに言うと、ベクトルと文字列の容量は、毎回1.5〜2倍に増加します。