2015-01-13 16 views
5

これはC++ 11固有の質問です。 ベクトルstd::vector<T> vがすでに使用されており、nの要素を既定の値T valで初期化するようにサイズを変更したいとします。 (典型的なusecase:ベクトルはリサイクルされるインスタンスのメンバーです)。std :: vector <T> :: resize(n、val)は初期化に十分ですか?

以下の方法の長所と短所は何か、最も効率的です。

1)std::vector<T>::resize(n, val)は初期化に十分ですか?

v.clear(); 
v.resize(n, val); 

2)そうでない場合は、以下が正しいと思いますか?

v.clear(); 
v.resize(n); 
std::fill(v.begin(), v.end(), val); 

3)交換はどうですか?

v.swap(std::vector<T>(n, val)); 
+1

これが重複している場合、私はそれを閉じるために投票よ、ソリューションにリンクしてください。 – Sheljohn

+0

サイズを変更したいのはなぜですか?メモリを解放するには? – edmz

+0

@black典型的なケース:これはクラスメンバであり、インスタンスをリサイクルしています。 – Sheljohn

答えて

5

(4)

std::fill(v.begin(), std::min(v.begin() + n, v.end()), val); 
v.resize(n, val); 

をTは、新しいものを構築するよりも少なくとも安価である適切な割り当て挙動を有する場合、(4)を使用します。これは、T = int(代入と構成が同じ)とT = std :: stringの場合です(既存のバッファを使用できるため、代入は構築より高速です)。

Tが同じ代入と構成(たとえばT = int)のコストを持つ場合、(1)はパフォーマンスを損なうことなく明快にするためにも使用できます。

Tを割り当てることができない、または、何らかの理由で、割り当てが構成よりも高価である場合(まれ)、次いで(1)

を使用する(1)〜(@Caseyに賛辞を)v.assign(n, val);を使用することによって簡略化することができる

(4)がassignを使用して同じパフォーマンス上のものであるかどうかわかりません。私は、割り当てられているかどうかわかりません(皮肉なことに、名前を付けて)新しい要素を既存の要素に割り当てるか、またはそれらを新たに構築します。

編集:テストしていない(4)の改善点。ベクトル容量の変更中にコピー/移動のオーバーヘッドを避けることができます。

if (n <= v.capacity()) 
{ 
    std::fill(v.begin(), std::min(v.begin() + n, v.end()), val); 
    v.resize(n, val); 
} 
else 
{ 
    v.assign(n, val); 
} 
+0

もしnが現在のサイズより大きければ、4は唯一有利だと思いますか? – Sheljohn

+0

@ Sh3ljohnよく調べましたが、(4) –

+0

を更新しました。n>古いサイズの場合は、 'v.end()'を超えて書き込みを行うことができますか? –

3

(1)で十分です。 (3)も働く。違いは、(1)新しいサイズが現在のサイズより小さければメモリを解放しないということです。 (3)常に新しいメモリのチャンクを割り当て、古いものを削除します。 (1)よりも遅いのは、まず要素をデフォルトで構成してから割り当てを行うためです。 Tがデフォルト構成可能でない場合、コンパイルされないこともあります。

+0

良い:)私は練習と_ad hoc_テストは、ケースに応じて(1)と(3)の間で決定すると思います。 – Sheljohn

+1

Tがシ​​ンプルならば、3は最悪のパフォーマンスです。 –

3

それぞれの違いを表示するために、それを分解してください。新しいサイズとしてnを使用します。古いサイズはmです。

1.

v.clear();//keeps the same buffer, but calls the destructor on all the values 
v.resize(n, val);//only makes a new buffer if the value is bigger, does no moves. 

2.

v.clear();//keeps the same buffer, but calls the destructor on all the values 
v.resize(n);//initializes all the values to default 
std::fill(v.begin(), v.end(), val);//initializes all the values again to the new value 

3.

v.swap(std::vector<T>(n, val));//calls destructor on all values in v, cannot reuse the buffer, initializes all the values to the new value 

違いは微妙ですが、本当です。 1 ですが、メモリのオーバーヘッドを節約できるバッファを再利用することはできません。 2は1と同じですが、二重再初期化を行います。 3は1と同じですが、バッファを再利用することはできません。

個人的には、3つの違いはほとんどの場合問題になるほど微妙であり、1が最も読みやすいと思います。

+0

非常に良い、と1対3の個人的な意見をありがとう:) – Sheljohn

+0

1は、バッファを再利用することが保証されています。 –

+0

@NeilKirk iff n <= m、コードで指定されていません。その場合、割り当ては破棄と再初期化よりも速くなる可能性があるので、彼はサイズ変更を行うべきではありません。 – IdeaHat

8

なぜこの仕事に合わせて設計されたインターフェイスを使用しないのですか?

v.assign(n, val); 

Documentation Here

+0

この関数がベクトルに既に存在する要素に対して代入演算子を使用することが保証されていますか? –

+0

実装はライブラリ実装者の責任です。標準では、どのように動作しなければならないかは規定されていない。私はそれが既存のアイテムの割り当て、新しいもののインプレースコピー構築、そして結果としてベクトルが縮小されればインサイド破壊を期待します。 –

+0

保証されていない場合は、最も効果的な方法ではない可能性があります。 –

関連する問題