Pergunta

Eu tenho um std :: vector m_vPaths; I irá iterar este vetor e chamada :: DeleteFile (strPath) como eu ir. Se eu excluir o arquivo com êxito, vou removê-lo do vetor. A minha pergunta é que eu posso dar a volta ter que usar dois vetores? Existe estrutura de dados diferente que poderia ser mais adequado para o que eu preciso fazer?

exemplo: usando iteradores quase faz o que eu quero, mas o problema é quando você apagar usando um iterador, todos os iteradores se tornar inválido.

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

Eu posso usar dois vetores e eu já não vai ter um problema, mas existe um método melhor, mais eficiente de fazer o que estou tentando fazer?

btw, meter não está claro, m_vPaths é declarado como este (em minha classe):

std::vector<std::string> m_vPaths;
Foi útil?

Solução

Confira 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());

Use a std::list para parar o problema iterators inválido, embora você perde aleatório Acesso. (E o desempenho do cache, em geral)


Para o registro, o modo como você poderia implementar o código seria:

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

Mas você deve usar std::remove_if (reinventar a roda é ruim).

Outras dicas

erase() método retorna uma nova (válidos) iterador que pontos para o próximo elemento após o apagado um. Você pode usar este iterador para continuar com o loop:

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

Dado o tempo para apagar um arquivo, ele provavelmente não importa, mas eu ainda gostaria orientar a iteração através das costas do vetor - de que maneira você está excluindo normalmente itens de (cerca de) o fim do vetor. O tempo necessário para excluir um item é proporcional ao número de itens que o seguem no vetor. Se (por exemplo) você tem um vetor de 100 nomes de arquivo e eliminar com sucesso todos eles, você vai copiar o último elemento 100 vezes no processo (e copiar o segundo ao último elemento de 99 vezes, e assim por diante).

OTOH, se você começar a partir do final e trabalhar para trás, você não copiar enquanto apagando os arquivos é bem sucedida. Você pode usar iteradores reversos para atravessar os para trás vetor sem mudar muito do que qualquer outra coisa. Por exemplo, o código de GMan usando remove_if deve continuar a trabalhar (apenas um pouco mais rápido) simplesmente substituindo rbegin () para começar () e rend () para o final.

Outra possibilidade é usar um deque em vez de um vetor -. Um deque pode apagar itens a partir do final ou o início da coleção em tempo constante

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top