Estoy usando std :: queue para implementar la clase JobQueue. (Básicamente, esta clase procesa cada trabajo de manera FIFO). En un escenario, quiero borrar la cola de una vez (eliminar todos los trabajos de la cola). No veo ningún método claro disponible en la clase std :: queue.
¿Cómo implemento eficientemente el método claro para la clase JobQueue?
Tengo una solución simple de aparecer en un bucle pero estoy buscando mejores formas.
//Clears the job queue
void JobQueue ::clearJobs()
{
// I want to avoid pop in a loop
while (!m_Queue.empty())
{
m_Queue.pop();
}
}
deque
admite clearRespuestas:
Un modismo común para borrar contenedores estándar es intercambiar con una versión vacía del contenedor:
También es la única forma de borrar realmente la memoria contenida en algunos contenedores (std :: vector)
fuente
std::queue<int>().swap(q)
. Con copiar y cambiar idioma, todo esto debería ser equivalente aq = std::queue<int>()
.std::queue<int>().swap(q)
es equivalente al código anterior,q = std::queue<int>()
no es necesario que sea equivalente. Dado que no hay transferencia de propiedad en la asignación de la memoria asignada, algunos contenedores (como el vector) podrían simplemente llamar a los destructores de los elementos previamente almacenados y establecer el tamaño (u operación equivalente con los punteros almacenados) sin liberar realmente la memoria.queue
no tiene unswap(other)
método, por loqueue<int>().swap(q)
que no compila. Creo que tienes que usar el genéricoswap(a, b)
.Sí, una mala característica de la clase de cola, en mi humilde opinión. Esto es lo que hago:
fuente
swap
es "más efectivo"q1.swap(queue<int>());
q1=queue<int>();
es a la vez más corto y más claro (en realidad no lo estás intentando.swap
, lo estás intentando.clear
).q1 = {}
es suficientequeue<T>
constructor predeterminado coincide con la lista de argumentos vacía{}
y es implícito, por lo que se llama, luegoq1.operator=(queue<T>&&)
consume el recién creadoqueue
El autor del tema preguntó cómo borrar la cola "eficientemente", por lo que supongo que quiere una mayor complejidad que el O lineal (tamaño de la cola) . Los métodos servidos por David Rodríguez , anon tienen la misma complejidad: de acuerdo con la referencia de STL,
operator =
tiene complejidad O (tamaño de la cola) . En mi humilde opinión es porque cada elemento de la cola se reserva por separado y no se asigna en un gran bloque de memoria, como en el vector. Entonces, para borrar toda la memoria, tenemos que eliminar cada elemento por separado. Entonces, la forma más directa de despejarstd::queue
es una línea:fuente
O(n^2)
algoritmo sobre unO(n)
algoritmo si las constantes en la operación lineal lo hacen más lento que el cuadrático para todosn < 2^64
, a menos que tenga una buena razón para creer que tuve que buscar el espacio de direcciones IPv6 o algún otro problema específico. El rendimiento en realidad es más importante para mí que el rendimiento al límite.Aparentemente, hay dos formas más obvias de borrar
std::queue
: intercambiar con objeto vacío y asignar a objeto vacío.Sugeriría usar la asignación porque es simplemente más rápida, más legible y sin ambigüedades.
Medí el rendimiento usando el siguiente código simple y descubrí que el intercambio en la versión C ++ 03 funciona un 70-80% más lento que la asignación a un objeto vacío. Sin embargo, en C ++ 11 no hay diferencia en el rendimiento. De todos modos, iría con la asignación.
fuente
En C ++ 11 puede borrar la cola haciendo esto:
fuente
Puede crear una clase que herede de la cola y borrar el contenedor subyacente directamente. Esto es muy eficiente.
Tal vez su implementación también permita que su objeto Queue (aquí
JobQueue
) herede enstd::queue<Job>
lugar de tener la cola como una variable miembro. De esta manera, tendría acceso directo ac.clear()
sus funciones de miembro.fuente
Suponiendo que
m_Queue
contiene enteros:De lo contrario, si contiene, por ejemplo, punteros a
Job
objetos, entonces:De esta manera, intercambia una cola vacía con su
m_Queue
, por lo tanto,m_Queue
queda vacía.fuente
Prefiero no confiar
swap()
o configurar la cola en un objeto de cola recién creado, porque los elementos de la cola no se destruyen correctamente. Llamarpop()
invoca al destructor para el objeto del elemento respectivo. Esto podría no ser un problema en las<int>
colas, pero podría tener efectos secundarios en las colas que contienen objetos.Por lo tanto, un bucle con
while(!queue.empty()) queue.pop();
parece ser, por desgracia, la solución más eficiente, al menos para las colas que contienen objetos si desea evitar posibles efectos secundarios.fuente
swap()
o la asignación llama al destructor en la cola ahora desaparecida, que llama a los destructores de todos los objetos en la cola. Ahora, si su cola tiene objetos que en realidad son punteros, ese es un problema diferente, pero un simplepop()
tampoco lo ayudará allí.Hago esto (usando C ++ 14):
Esta forma es útil si tiene un tipo de cola no trivial para el que no desea construir un alias / typedef. Sin embargo, siempre me aseguro de dejar un comentario sobre este uso para explicar a los programadores desprevenidos / de mantenimiento que esto no es una locura y que se realiza en lugar de un
clear()
método real .fuente
myqueue = { };
funcionará bien.Usar un
unique_ptr
podría estar bien.Luego lo reinicia para obtener una cola vacía y libera la memoria de la primera cola. ¿En cuanto a la complejidad? No estoy seguro, pero supongo que es O (1).
Código posible:
fuente
Otra opción es usar un truco simple para obtener el contenedor subyacente
std::queue::c
y llamarloclear
. Este miembro debe estar presentestd::queue
según el estándar, pero desafortunadamente está presenteprotected
. El truco aquí fue tomado de esta respuesta .fuente