質問

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 つの可能性は、ベクトルの代わりに両端キューを使用することです。両端キューは項目を末尾から消去できます。 または 一定時間内のコレクションの開始。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top