2012-04-18 5 views
11

私は既存のvector要素のコピーをそれを倍増させるために挿入しようとしています。次のコードは、以前のバージョンで働いていたが、2010年複製要素をベクトルに挿入するにはどうすればよいですか?

#include <iostream> 
#include <vector> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    vector<int> test; 
    test.push_back(1); 
    test.push_back(2); 
    test.insert(test.begin(), test[0]); 
    cout << test[0] << " " << test[1] << " " << test[2] << endl; 
    return 0; 
} 

出力が-17891602 1 2でのVisual Studioで失敗し、1 1 2を期待しました。

なぜそれが起こっているのかわかりました。ベクトルが再割り当てされ、参照が無効になって挿入ポイントにコピーされます。旧式のVisual Studioは明らかに異なる順序で動作していたため、未定義の動作の1つの可能な結果は、正しく動作することと、それが決して頼りになるものではないことが証明されています。

私はこの問題を解決する2つの方法を考え出しました。一つは何の再割り当てが行われないことを確認するreserveを使用することです:

test.reserve(test.size() + 1); 
    test.insert(test.begin(), test[0]); 

他には、有効な残りの参照には依存関係がありませんように、参照からコピーを作成することです。

template<typename T> 
T make_copy(const T & original) 
{ 
    return original; 
} 

    test.insert(test.begin(), make_copy(test[0])); 

が、いずれも自然な解決策のようには感じられません。私は行方不明のものがありますか?

+0

BTW vc11 dev previewは最初の例で '1 1 2'を返します。 –

+0

@Jesse、それは私を驚かさない。 'insert'のRvalueオーバーロードが選択されました。これは修正されたバグのようです。コードは、そのオーバーロードとconst参照を受け取るものとでは全く異なります。 –

+0

intへのキャストは機能しますか? –

答えて

1

これは定義された動作だと思います。 2011 C++標準の§23.2.3では、テーブル100はシーケンスコンテナの要件を示しており、この場合のエントリがあります。それは、例えばにaタイプTの要素を含む配列コンテナタイプであるXの値であり、paへのconstイテレータであり、そしてtタイプX::value_typeの左辺値またはconstの右辺値で表現

a.insert(p,t) 

を与えますすなわち、T

この表現のための主張は次のとおりです。

が必要です:TXCopyInsertableをしなければなりません。 vectorおよびdequeについては、TCopyAssignableでなければなりません。
効果:tのコピーをpの前に挿入します。

備考:新しいサイズが古い容量よりも大きい場合、再割り当て原因私は見つけることができる

のみ関連ベクトル特定の引用は§23.3.6.5第1項です。再割り当てが行われない場合、挿入ポイントの前のすべてのイテレータと参照は有効なままです。

これはベクトルが再割り当てされていることを示していますが、シーケンスコンテナの前の要件であるinsertの例外はありません。

この問題を回避するために、@ EdChumの要素のコピーを作成してそのコピーを挿入することに同意します。

+0

' t 'が 'a'のメンバへの参照である場合を説明するものはあなたの記述には何も表示されません。 –

4

問題は、vector::insertが値ではなく2番目のパラメータとして値を参照することです。テンプレートをコピーする必要はありません。コピーコンストラクタを使用して別のオブジェクトを作成するだけで、参照渡しとなります。このコピーは、ベクトルのサイズが変更されても有効です。

#include <iostream> 
#include <vector> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    vector<int> test; 
    test.push_back(1); 
    test.push_back(2); 
    test.insert(test.begin(), int(test[0])); 
    cout << test[0] << " " << test[1] << " " << test[2] << endl; 
    return 0; 
} 
+0

これは単なるテストケースです。私の実際のコードには、intよりはるかに複雑な要素が含まれており、一時的なコンストラクタはちょっと醜いです。しかし、良い提案。 –