1

この振る舞いを説明することはできません:

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) erase(it); // break after, no need of ++it in else branch
}

ここで、File は自分のクラス (std は含まれていません) であり、this->files は Files のベクトルです

取得したコードをコンパイルすると (行 2を参照)

Path.cpp: In member function ‘void Path::rmFile(File&)’:
Path.cpp:190:24: error: no matching function for call to ‘std::vector<File>::erase(std::vector<File>::const_iterator&)’
Path.cpp:190:24: note: candidates are:
In file included from /usr/include/c++/4.7/vector:70:0,
             from Path.h:5,
             from Path.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:135:5: note: std::vector<_Tp, _Alloc>::iterator     std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = File; _Alloc =     std::allocator<File>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<File*,     std::vector<File> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = File*]
/usr/include/c++/4.7/bits/vector.tcc:135:5: note:   no known conversion for argument 1     from ‘std::vector<File>::const_iterator {aka __gnu_cxx::__normal_iterator<const File*,     std::vector<File> >}’ to ‘std::vector<File>::iterator {aka __gnu_cxx::__normal_iterator<File*,     std::vector<File> >}’
/usr/include/c++/4.7/bits/vector.tcc:147:5: note: std::vector<_Tp, _Alloc>::iterator     std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp,     _Alloc>::iterator) [with _Tp = File; _Alloc = std::allocator<File>; std::vector<_Tp,     _Alloc>::iterator = __gnu_cxx::__normal_iterator<File*, std::vector<File> >; typename     std::_Vector_base<_Tp, _Alloc>::pointer = File*]
/usr/include/c++/4.7/bits/vector.tcc:147:5: note:   candidate expects 2 arguments, 1 provided
make: *** [Path.o] Error 1

ドキュメントでさえ問題ない と言っていますが、 std::vector::erase(std::vector::const_iterator&) の呼び出しに一致する関数がないというエラーは本当に奇妙です。

ベクターアイテムをイテレータで削除できるようにする必要があります。誰でも私を助けてもらえますか?あらかじめご了承ください。

4

2 に答える 2

4

ここに 3 つのバグがあります。

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) erase(it); // break after, no need of ++it in else branch
}

最初のバグは、コードを StackOverflow に誤ってカット アンド ペーストしたことです。あなたが貼り付けるつもりだったのは

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) this->files.erase(it); // break after, no need of ++it in else branch
}

2 番目のバグは、コンパイラが警告しているものです。. を介してコレクションを変更する方法はありませんconst_iterator。(編集:わかりました、どうやらC++ 11はそのような方法を追加しましたが、libstdc ++はすぐにはサポートしませんでした。)それがそのconst_部分の意味です!コレクションを変更したい場合は、プレーンな古いものを使用してiteratorください:

for (vector<File>::iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) this->files.erase(it); // LOOK OUT, THERE'S STILL A BUG
}

3 つ目のバグは、コレクションを呼び出すstd::vector::eraseと、そのコレクションのすべての反復子 (およびconst_iterators) が unusable になることです。これに対する標準的な用語は、erase イテレータを無効にするというものです。(これの理由は、std::vector基本的に大きなヒープ割り当てバッファのように動作し、ベクトルでの呼び出しはバッファで(1)resizeと同等のことを行うことが許可され、呼び出しは呼び出しが許可されているためです(要素の半分をベクトル、それに応じてヒープ割り当てが縮小することをおそらく期待しているでしょう))。realloceraseresizeerase

したがって、あなたがやろうとしていることは、単純な for ループ アプローチを使用しては機能しません。あなたがする必要があるのは、標準のアルゴリズムを使用することです。remove_if

#include <algorithm>

auto predicate = [](const File& f) { return f.ShouldBeErasedOrWhatever(); }
auto newEndIterator = std::remove_if(this->files.begin(), this->files.end(), predicate);
this->files.erase(newEndIterator, this->files.end());  // erase everything after "newEndIterator"

元のコードの " " に置き換えf.ShouldBeErasedOrWhatever()てください。...これで、正しいことを行う有効で慣用的な C++11 が手に入りました — バグはありません!


(1) – 「と同等のもの」に関する注意realloc: もちろん、実際にはそうではありませ realloc。これは実際には、必要に応じてムーブ コンストラクターとデストラクターを呼び出すタイプ セーフなプロセスです。一般に、C++ の任意のオブジェクトに対してvector安全ではないことを知っています。memcpy

于 2013-12-01T03:17:27.943 に答える