web-dev-qa-db-ja.com

std :: vector要素は連続していることが保証されていますか?

私の質問は簡単です:std :: vector要素は連続していることが保証されていますか? Wordで、std :: vectorの最初の要素へのポインターをC配列として使用できますか?

私の記憶が私によく役立つなら、C++標準はそのような保証をしませんでした。ただし、std :: vectorの要件は、要素が連続していない場合に満たすことは事実上不可能でした。

誰かがこれを明確にすることはできますか?

例:

std::vector<int> values;
// ... fill up values

if( !values.empty() )
{
    int *array = &values[0];
    for( int i = 0; i < values.size(); ++i )
    {
        int v = array[i];
        // do something with 'v'
    }
}
100
Martin Cote

これはC++ 98標準からは見逃されていましたが、後にTRの一部として追加されました。もちろん、今後のC++ 0x標準にはこれが要件として含まれます。

N2798(C++ 0xのドラフト)から:

23.2.6クラステンプレートベクトル[ベクトル]

1ベクトルは、ランダムアクセス反復子をサポートするシーケンスコンテナーです。さらに、最後の(償却済み)一定時間の挿入および消去操作をサポートします。中央に挿入して消去すると、線形の時間がかかります。ストレージ管理は自動的に処理されますが、効率を改善するためのヒントを提供できます。ベクトルの要素は連続して格納されます。つまり、vがTがbool以外のタイプのベクトルの場合、すべての0 <= n <vに対して&v [n] ==&v [0] + nのアイデンティティに従います。 。サイズ()。

103
dirkgently

他の答えが指摘したように、ベクトルの内容は連続していることが保証されています(boolの奇妙さを除く)。

私が追加したいコメントは、ベクターでメモリの再割り当てを引き起こす可能性のあるベクターで挿入または削除を行うと、保存されたすべてのポインターとイテレーターが無効になるということです。

19
Bill Lynch

実際、標準では、vectorがメモリ内で連続的であり、&a[0]が配列を想定するC関数に渡されることを保証しています。

この規則の例外はvector<bool>で、boolごとに1ビットのみを使用します。したがって、連続メモリはありますが、bool*として使用することはできません(これは広く考えられています誤った最適化と間違い)。

ところで、なぜイテレータを使用しないのですか?それが彼らの目的です。

7
Motti

他の人がすでに言ったように、vectorは内部的に連続したオブジェクトの配列を使用します。その配列へのポインターは、非constメンバー関数がIIRCと呼ばれる場合は常に無効として扱われるべきです。

ただし、例外があります!!

vector<bool>には、スペースを節約するために設計された特殊な実装があり、各ブールは1ビットのみを使用します。基礎となる配列はブールの連続配列ではなく、vector<bool>の配列演算はvector<T>のようには機能しません。

(これはベクトルの特殊化にも当てはまると考えられます。常に新しいものを実装できるからです。ただし、std::vector<bool>のみが、単純なポインター演算が機能しない標準の特殊化です。 )

5
Wuggy

このスレッドを見つけたのは、連続メモリを使用するベクターが利点であるユースケースがあるためです。

OpenGLで頂点バッファーオブジェクトを使用する方法を学んでいます。バッファーロジックを含めるラッパークラスを作成したので、必要なのは、floatの配列といくつかの構成値を渡してバッファーを作成することだけです。ユーザー入力に基づいて関数からバッファを生成できるようにしたいので、コンパイル時に長さがわかりません。このようなことをするのが最も簡単な解決策です:

void generate(std::vector<float> v)
{
  float f = generate_next_float();
  v.Push_back(f);
}

これで、ベクターの浮動小数点数を配列としてOpenGLのバッファー関連関数に渡すことができます。これにより、sizeofを使用して配列の長さを決定する必要もなくなります。

これは、フロートを格納するために巨大な配列を割り当てて、十分に大きくしたり、連続したストレージで独自の動的配列を作成したりすることを望んでいます。

3
NobodyImportant

はい、std :: vectorの要素は連続していることが保証されています。

2
Benoît

cplusplus.com:

ベクトルコンテナーは動的配列として実装されます。通常の配列と同様に、ベクトルコンテナーの要素は連続した格納場所に格納されます。つまり、イテレーターだけでなく、要素への通常のポインターのオフセットを使用して要素にアクセスできます。

1
Igor Oks