выполните итерации вектора, удалите определенные объекты, когда я иду

У меня есть станд.:: вектор m_vPaths; я выполню итерации этого вектора и вызова:: DeleteFile (strPath), когда я иду. Если я успешно удалю файл, то я удалю его из вектора. Моим вопросом является банка, я обхожу необходимость использовать два вектора? Есть ли другая структура данных, которая могла бы лучше подойти для того, что я должен сделать?

пример: использование итераторов почти делает то, что я хочу, но проблема состоит в том, после того как Вы стираете использование итератора, все итераторы становятся недопустимыми.

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

Я могу использовать два вектора, и я больше не буду иметь проблемы, но являюсь там лучшим, более эффективным способом выполнения, что я пытаюсь сделать?

btw, упакуйте его, неясно, m_vPaths объявляется как это (в моем классе):

std::vector<std::string> m_vPaths;
62
задан 29 August 2013 в 02:05

3 ответа

Выезд 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 (изобретение велосипед плохо).

75
ответ дан 31 October 2019 в 13:10

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;
}
119
ответ дан 31 October 2019 в 13:10

Учитывая время для стирания файла это, вероятно, не имеет значения, но я все еще советовал бы выполнять итерации через вектор назад - тот способ, из которого Вы обычно удаляете объекты (близко к) концу вектора. Время, потраченное для удаления объекта, пропорционально количеству объектов после него в векторе. Если (например), у Вас будет вектор 100 имен файлов, и Вы успешно удаляете всех их, то Вы скопируете последний элемент 100 раз в процессе (и скопируете предпоследний элемент 99 раз, и так далее).

OTOH, если Вы запускаете с конца и работаете назад, Вы не копируете, пока удаление файлов успешно. Можно использовать обратные итераторы для пересечения вектора назад, не изменяя большую часть ничего больше. Например, код GMAN с помощью remove_if должен продолжить работать (только немного быстрее) просто путем замены rbegin () для, начинаются () и разрывают () для конца.

Другая возможность состоит в том, чтобы использовать двухстороннюю очередь вместо вектора - двухсторонняя очередь может стереть объекты из конца или начало набора в постоянное время.

7
ответ дан 31 October 2019 в 13:10

Другие вопросы по тегам:

Похожие вопросы: