Estou usando std :: fila para implementar a classe JobQueue. (Basicamente, essa classe processa cada trabalho da maneira FIFO). Em um cenário, desejo limpar a fila de uma só vez (exclua todos os trabalhos da fila). Não vejo nenhum método claro disponível na classe std :: queue.
Como implemento eficientemente o método claro para a classe JobQueue?
Eu tenho uma solução simples de aparecer em um loop, mas estou procurando maneiras melhores.
//Clears the job queue
void JobQueue ::clearJobs()
{
// I want to avoid pop in a loop
while (!m_Queue.empty())
{
m_Queue.pop();
}
}
deque
suporta claraRespostas:
Um idioma comum para limpar contêineres padrão é trocar por uma versão vazia do contêiner:
Também é a única maneira de limpar a memória mantida dentro de alguns contêineres (std :: vector)
fonte
std::queue<int>().swap(q)
. Com o idioma copy e swap, tudo isso deve ser equivalente aq = std::queue<int>()
.std::queue<int>().swap(q)
seja equivalente ao código acima,q = std::queue<int>()
não precisa ser equivalente. Como não há transferência de propriedade na atribuição da memória alocada, alguns contêineres (como vetor) podem chamar os destruidores dos elementos mantidos anteriormente e definir o tamanho (ou operação equivalente com os ponteiros armazenados) sem realmente liberar a memória.queue
não possui umswap(other)
método, portantoqueue<int>().swap(q)
não compila. Eu acho que você tem que usar o genéricoswap(a, b)
.Sim - um pouco de uma característica incorreta da classe da fila, IMHO. Isto é o que eu faço:
fonte
swap
é "mais eficaz"q1.swap(queue<int>());
q1=queue<int>();
é mais curto e mais claro (você não está realmente tentando.swap
, está tentando.clear
).q1 = {}
é suficientequeue<T>
construtor padrão corresponde à lista de argumentos vazia{}
e está implícito, por isso é chamado e, em seguida,q1.operator=(queue<T>&&)
consome o recém-criadoqueue
O autor do tópico perguntou como limpar a fila "eficientemente", então suponho que ele queira uma complexidade melhor que O linear (tamanho da fila) . Métodos servidos por David Rodriguez , Anon tem a mesma complexidade: de acordo com a referência STL,
operator =
tem complexidade O (fila de tamanho) . IMHO é porque cada elemento da fila é reservado separadamente e não é alocado em um grande bloco de memória, como no vetor. Portanto, para limpar toda a memória, precisamos excluir todos os elementos separadamente. Portanto, a maneira mais direta de limparstd::queue
é uma linha:fonte
O(n^2)
algoritmo sobre umO(n)
algoritmo se as constantes na operação linear o tornassem mais lento que o quadrático para todosn < 2^64
, a menos que eu tivesse algum motivo forte para acreditar que tinha que pesquisar no espaço de endereço IPv6 ou algum outro problema específico. O desempenho na realidade é mais importante para mim do que o desempenho no limite.Aparentemente, existem duas maneiras mais óbvias de limpar
std::queue
: trocar com objeto vazio e designar para objeto vazio.Eu sugeriria usar a atribuição porque ela é simplesmente mais rápida, mais legível e inequívoca.
Avaliei o desempenho usando o código simples a seguir e descobri que a troca na versão C ++ 03 funciona 70-80% mais lenta que a atribuição a um objeto vazio. No C ++ 11, no entanto, não há diferença no desempenho. Enfim, eu iria com atribuição.
fonte
No C ++ 11, você pode limpar a fila fazendo o seguinte:
fonte
Você pode criar uma classe que herda da fila e limpar o contêiner subjacente diretamente. Isto é muito eficiente.
Talvez sua implementação também permita que o objeto Fila (aqui
JobQueue
) seja herdado emstd::queue<Job>
vez de ter a fila como uma variável membro. Dessa forma, você teria acesso direto àsc.clear()
suas funções de membro.fonte
Supondo que você
m_Queue
contenha números inteiros:Caso contrário, se ele contiver, por exemplo, ponteiros para
Job
objetos, então:Dessa forma, você troca uma fila vazia pelo seu e
m_Queue
, assim,m_Queue
fica vazia.fonte
Prefiro não confiar
swap()
ou definir a fila para um objeto de fila criado recentemente, porque os elementos da fila não são destruídos adequadamente. A chamadapop()
chama o destruidor para o respectivo objeto do elemento. Isso pode não ser um problema nas<int>
filas, mas pode muito bem ter efeitos colaterais nas filas que contêm objetos.Portanto,
while(!queue.empty()) queue.pop();
infelizmente, um loop com parece ser a solução mais eficiente, pelo menos para filas contendo objetos, se você deseja evitar possíveis efeitos colaterais.fonte
swap()
ou atribuição chama o destruidor na fila agora extinta, que chama os destruidores de todos os objetos na fila. Agora, se sua fila tiver objetos que realmente são ponteiros, isso é um problema diferente - mas um simplespop()
também não ajudará você.Eu faço isso (usando C ++ 14):
Dessa forma, é útil se você tiver um tipo de fila não trivial para o qual não deseja criar um alias / typedef. Eu sempre certifique-se de deixar um comentário sobre esse uso, no entanto, para explicar aos programadores desavisados / de manutenção que isso não é loucura e feito em vez de um
clear()
método real .fonte
myqueue = { };
funcionará bem.Usar um
unique_ptr
pode estar OK.Você o redefine para obter uma fila vazia e liberar a memória da primeira fila. Quanto à complexidade? Não tenho certeza - mas acho que é O (1).
Código possível:
fonte
Outra opção é usar um hack simples para obter o contêiner subjacente
std::queue::c
e acessáclear
-lo. Esse membro deve estar presente destd::queue
acordo com o padrão, mas infelizmente estáprotected
. O hack aqui foi retirado desta resposta .fonte