Frage

Ich habe ein std :: vector m_vPaths; Ich werde diesen Vektor laufen und rufen :: DeleteFile (strPath), wie ich gehen. Wenn ich die Datei erfolgreich löschen, ich werde es aus dem Vektor entfernen. Meine Frage ist, kann ich umgehen mit zwei Vektoren benutzen? Gibt es unterschiedliche Datenstruktur, die besser geeignet sein könnte für das, was ich tun muß?

Beispiel: mit Iteratoren fast tut, was ich will, aber Problem ist, wenn Sie einen Iterator löschen verwenden, werden alle Iteratoren ungültig.

 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.    
        }
    }

kann ich zwei Vektoren verwendet werden, und ich werde nicht mehr ein Problem haben, aber gibt es ein besseres, effizientere Verfahren zu tun, was ich tun werde versuchen?

btw, einhüllen es unklar ist, wird m_vPaths wie folgt erklärt (in meiner Klasse):

std::vector<std::string> m_vPaths;
War es hilfreich?

Lösung

Schauen Sie sich 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());

Verwenden Sie einen std::list die ungültige Iteratoren Problem zu stoppen, wenn Sie zufällig verlieren Zugriff. (Und Cache-Leistung, im Allgemeinen)


Für das Protokoll, wie Sie Ihren Code implementieren würde wäre:

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;
    }
}

Aber Sie sollten verwenden std::remove_if (das Rad neu erfinden ist schlecht).

Andere Tipps

Die erase() Methode gibt einen neuen (gültig) Iterator, dass die Punkte auf das nächste Element nach den gelöschten eins. Sie können diese Iterator verwenden, um mit der Schleife, um fortzufahren:

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;
}

die Zeit gegeben, eine Datei zu löschen, ist es wahrscheinlich keine Rolle, aber ich würde immer noch durch den Vektor rate Iterieren nach hinten - diese Art und Weisen Sie normalerweise Elemente aus (in der Nähe) das Ende des Vektors zu löschen. Die Zeit, die ein Element zu löschen, ist proportional zu der Anzahl der Elemente in dem Vektor folgen. Wenn (zum Beispiel) ein Vektor von 100 Dateinamen haben, und Sie erfolgreich alle löschen, werden Sie das letzte Element 100 Mal im Prozess kopieren (und die zweiten zum letzten Elemente 99 mal kopieren, und so weiter).

OTOH, wenn man vom Ende beginnen und nach hinten arbeiten, müssen Sie nicht so lange kopieren, wie das Löschen der Dateien erfolgreich war. Sie können Reverse-Iteratoren verwenden, um den Vektor durchqueren rückwärts ohne sonst so gut wie nichts zu ändern. Zum Beispiel sollte GMan Code remove_if mit weiter arbeitet (nur ein bisschen schneller) einfach durch Substitution rbegin () für begin () und Rend () zum Ende.

Eine andere Möglichkeit ist es, eine deque anstelle eines Vektors zu verwenden - a. Deque können Elemente aus dem Ende löschen oder der Beginn der Sammlung in konstanten Zeit

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top