ベクトルを反復し、特定の項目を削除します
-
05-07-2019 - |
質問
std::vector m_vPaths があります。このベクトルを繰り返して、::DeleteFile(strPath) を呼び出します。ファイルの削除に成功したら、ベクターから削除します。私の質問は、2 つのベクトルを使用する必要を回避できるかということです。私が行う必要があることに適した別のデータ構造はありますか?
例:イテレータを使用するとほぼ希望通りの結果が得られますが、問題は、イテレータを使用して消去すると、すべてのイテレータが無効になってしまうことです。
std::vector<std::string> iter = m_vPaths.begin();
for( ; iter != m_vPaths.end(); iter++) {
std::string strPath = *iter;
if(::DeleteFile(strPath.c_str())) {
m_vPaths.erase(iter);
//Now my interators are invalid because I used erase,
//but I want to continue deleteing the files remaining in my vector.
}
}
2 つのベクトルを使用できるので問題はなくなりましたが、私がやろうとしていることを実行するための、より適切で効率的な方法はあるでしょうか?
ところで、不明瞭な場合に備えて、m_vPaths は次のように宣言されます (私のクラスでは)。
std::vector<std::string> m_vPaths;
解決
std :: remove_if
をチェックアウトします。
#include <algorithm> // for remove_if
#include <functional> // for unary_function
struct delete_file : public std::unary_function<const std::string&, bool>
{
bool operator()(const std::string& strPath) const
{
return ::DeleteFile(strPath.c_str());
}
}
m_vPaths.erase(std::remove_if(m_vPaths.begin(), m_vPaths.end(), delete_file()),
m_vPaths.end());
std :: list
を使用して、ランダムアクセスが失われますが、無効な反復子の問題を停止します。 (そして一般的にキャッシュのパフォーマンス)
レコードの場合、コードを実装する方法は次のとおりです。
typedef std::vector<std::string> string_vector;
typedef std::vector<std::string>::iterator string_vector_iterator;
string_vector_iterator iter = m_vPaths.begin();
while (iter != m_vPaths.end())
{
if(::DeleteFile(iter->c_str()))
{
// erase returns the new iterator
iter = m_vPaths.erase(iter);
}
else
{
++iter;
}
}
ただし、 std :: remove_if
(車輪の再発明は悪い)。
他のヒント
erase()
メソッド削除された要素の後の次の要素を指す新しい(有効な)イテレータを返します。この反復子を使用して、ループを続行できます。
std::vector<std::string>::iterator iter;
for (iter = m_vPaths.begin(); iter != m_vPaths.end(); ) {
if (::DeleteFile(iter->c_str()))
iter = m_vPaths.erase(iter);
else
++iter;
}
ファイルを消去する時間を考えると、おそらく問題ではありませんが、ベクトルを逆方向に反復処理することをお勧めします。そうすることで、通常はベクトルの末尾 (近く) から項目を削除することになります。項目の削除にかかる時間は、ベクトル内でその項目に続く項目の数に比例します。(たとえば) 100 個のファイル名のベクトルがあり、すべてのファイルを正常に削除した場合、プロセス内で最後の要素を 100 回コピーします (最後から 2 番目の要素を 99 回コピーするなど)。
OTOH、最後から始めて逆方向に作業すると、ファイルの削除が成功する限りコピーされません。逆反復子を使用すると、他にほとんど変更を加えずにベクトルを逆方向に走査できます。たとえば、remove_if を使用する GMan のコードは、begin() を rbegin() に、end を rend() に置き換えるだけで、引き続き動作します (ほんの少しだけ高速になります)。
もう 1 つの可能性は、ベクトルの代わりに両端キューを使用することです。両端キューは項目を末尾から消去できます。 または 一定時間内のコレクションの開始。