2012-04-29 14 views
4

このサンプルプログラムは、別のベクトルに含まれるベクトルの要素に対するイテレータを取得します。私は含んでいるベクターに別の要素を追加して、以前に取得したイテレータの値をプリントアウト:foo_itにcorrespindingベクトルが、私はイテレータがまだ有効であることを期待して変更されていないのでネストされたベクトルを持つイテレータを使用すると予期しない動作が発生する

#include <vector> 
#include <iostream> 

int main(int argc, char const *argv[]) 
{ 
    std::vector<std::vector<int> > foo(3, std::vector<int>(3, 1)); 
    std::vector<int>::iterator foo_it = foo[0].begin(); 
    std::cout << "*foo_it: " << *foo_it << std::endl; 
    foo.push_back(std::vector<int>(3, 2)); 
    std::cout << "*foo_it: " << *foo_it << std::endl; 
    return 0; 
} 

。私はこのコードを実行すると、しかし、私は(もideoneに)次の出力を得る:参考

*foo_it: 1 
*foo_it: 0 

私はG ++バージョン4.2と4.6と同様に打ち鳴らす3.1を使用してこの結果を得ます。しかし、-std=c++0xideone link)とclangとを使用してg ++で期待される出力を得て、-std=c++0x-stdlib=libc++の両方を使用すると、出力が得られます。

ここで何らかの未定義の動作が呼び出されましたか?もしこれが今ではC++ 11の動作に定義されていますか?これは単にコンパイラ/標準ライブラリのバグですか?

編集ここで、C++ 03では、ベクトルの要素が再配置時にコピーされるため、イテレータが無効になることがわかりました。しかし、私はこれがC++ 11で有効かどうかを知りたがっています(つまり、コピーされる代わりにベクタの要素が確実に移動され、イテレータを無効にしないでベクトルを移動します)。

答えて

5

push_backは、イテレータを無効にします。

std::vector<int>::iterator foo_it = foo[0].begin(); 
foo.push_back(std::vector<int>(3, 2)); 

この後、foo_tiは有効ではなくなりました。 insert/push_backは、内部的にベクトルを再割り当てする可能性があります。

+0

また、 'operator []'で得られたものなど、ベクトルの要素へのポインタや参照を無効にします。 –

+0

彼はイテレータを持っている 'vector'に対して' push_back'を呼び出していません。 –

+0

@LuchianGrigore彼は 'foo [0] .begin()'を呼び出し、 'foo'ではなく' foo'に 'push_back'を呼び出します。 –

5

foo_itにcorrespindingベクターは

間違っ

を変更されていないので。 push_backは、foo_itに対応するベクターを破壊した。 foo[0]が破壊された場合、foo_itが無効になりました。

0

私は間違っていると思われます。ベクトル<ベクトル< int>はポインタのベクトルであり、外側のものが再割り当てされると内側のものへのポインタはまだ有効です。これは** intに対して真です。しかし、代わりにベクトルを再割り当てすると、すべての内部ベクトルが再割り当てされ、内部イテレータも無効になります。

+0

必ずしも真実ではありません。 (実際にはC++ 11では常にfalseです) –

+0

私はこれを2つの値のアドレスを出力してテストしました。これは、内部ベクトルからのデータが再割り当てされたことを意味します。 – guinny

+0

それはあなたが話しているアドレスに依存します。しかし、C++ 11では、 'std :: vector'はできるだけコピーを格納するのではなく、内部を移動しなければならず、移動操作はイテレータを無効にしたり、再配置を引き起こしたりしません。 –

関連する問題