J'utilise std :: queue pour implémenter la classe JobQueue. (Fondamentalement, cette classe traite chaque travail de manière FIFO). Dans un scénario, je souhaite effacer la file d'attente d'un seul coup (supprimer tous les travaux de la file d'attente). Je ne vois aucune méthode claire disponible dans la classe std :: queue.
Comment implémenter efficacement la méthode clear pour la classe JobQueue?
J'ai une solution simple de sauter dans une boucle mais je cherche de meilleures façons.
//Clears the job queue
void JobQueue ::clearJobs()
{
// I want to avoid pop in a loop
while (!m_Queue.empty())
{
m_Queue.pop();
}
}
deque
prend en charge clearRéponses:
Un idiome courant pour effacer les conteneurs standard consiste à échanger avec une version vide du conteneur:
C'est aussi le seul moyen d'effacer réellement la mémoire contenue dans certains conteneurs (std :: vector)
la source
std::queue<int>().swap(q)
. Avec copie et échange idiome, tout cela devrait être équivalent àq = std::queue<int>()
.std::queue<int>().swap(q)
soit équivalent au code ci-dessus, ilq = std::queue<int>()
n'est pas nécessaire que ce soit équivalent. Puisqu'il n'y a pas de transfert de propriété dans l'affectation de la mémoire allouée, certains conteneurs (comme vector) pourraient simplement appeler les destructeurs des éléments précédemment détenus et définir la taille (ou une opération équivalente avec les pointeurs stockés) sans réellement libérer la mémoire.queue
n'a pas deswap(other)
méthode, doncqueue<int>().swap(q)
ne compile pas. Je pense que vous devez utiliser le génériqueswap(a, b)
.Oui - un peu d'un dysfonctionnement de la classe de file d'attente, à mon humble avis. C'est ce que je fais:
la source
swap
est "plus efficace"q1.swap(queue<int>());
q1=queue<int>();
est à la fois plus court et plus clair (vous n'essayez pas vraiment de le faire.swap
, vous essayez de le faire.clear
).q1 = {}
assezqueue<T>
constructeur par défaut correspond à une liste d'arguments vide{}
et est implicite, il est donc appelé, puisq1.operator=(queue<T>&&)
consomme le nouvellement crééqueue
L'auteur du sujet a demandé comment effacer la file d'attente "efficacement", donc je suppose qu'il veut une meilleure complexité que O linéaire (taille de la file d'attente) . Les méthodes servies par David Rodriguez , anon, ont la même complexité: selon la référence STL,
operator =
a la complexité O (taille de la file d'attente) . À mon humble avis, c'est parce que chaque élément de la file d'attente est réservé séparément et qu'il n'est pas alloué dans un gros bloc de mémoire, comme dans le vecteur. Donc, pour effacer toute la mémoire, nous devons supprimer chaque élément séparément. Donc, la façon la plus directe de supprimerstd::queue
est une ligne:la source
O(n^2)
algorithme sur unO(n)
algorithme si les constantes de l'opération linéaire le rendent plus lent que le quadratique pour tousn < 2^64
, à moins que j'aie une bonne raison de croire que je devais rechercher l'espace d'adressage IPv6 ou un autre problème spécifique. La performance en réalité est plus importante pour moi que la performance à la limite.Apparemment, il existe deux façons les plus évidentes de supprimer
std::queue
: permutation avec un objet vide et affectation à un objet vide.Je suggérerais d'utiliser l'affectation parce que c'est simplement plus rapide, plus lisible et sans ambiguïté.
J'ai mesuré les performances en utilisant le code simple suivant et j'ai trouvé que l'échange dans la version C ++ 03 fonctionne 70 à 80% plus lentement que l'assignation à un objet vide. En C ++ 11, il n'y a cependant aucune différence de performances. Quoi qu'il en soit, j'irais avec une mission.
la source
Dans C ++ 11, vous pouvez effacer la file d'attente en procédant comme suit:
la source
Vous pouvez créer une classe qui hérite de la file d'attente et effacer directement le conteneur sous-jacent. C'est très efficace.
Peut-être que votre implémentation permet également à votre objet Queue (ici
JobQueue
) d'hériterstd::queue<Job>
au lieu d'avoir la file d'attente comme variable membre. De cette façon, vous auriez un accès direct àc.clear()
vos fonctions membres.la source
En supposant que votre
m_Queue
contient des entiers:Sinon, s'il contient par exemple des pointeurs vers des
Job
objets, alors:De cette façon, vous permutez une file d'attente vide avec votre
m_Queue
, devenant ainsim_Queue
vide.la source
Je préfère ne pas compter sur
swap()
ou définir la file d'attente sur un objet de file d'attente nouvellement créé, car les éléments de la file d'attente ne sont pas correctement détruits. L'appelpop()
appelle le destructeur de l'objet d'élément respectif. Cela peut ne pas être un problème dans les<int>
files d'attente, mais peut très bien avoir des effets secondaires sur les files d'attente contenant des objets.Par conséquent, une boucle avec
while(!queue.empty()) queue.pop();
semble malheureusement être la solution la plus efficace au moins pour les files d'attente contenant des objets si vous voulez éviter d'éventuels effets secondaires.la source
swap()
ou affectation appelle le destructeur de la file d'attente maintenant disparue, qui appelle les destructeurs de tous les objets de la file d'attente. Maintenant, si votre file d'attente contient des objets qui sont en fait des pointeurs, c'est un problème différent - mais un simplepop()
ne vous aidera pas non plus.Je fais ceci (en utilisant C ++ 14):
Cette méthode est utile si vous avez un type de file d'attente non trivial pour lequel vous ne souhaitez pas créer d'alias / typedef. Je m'assure toujours de laisser un commentaire sur cette utilisation, cependant, pour expliquer aux programmeurs sans méfiance / de maintenance que ce n'est pas fou et que ce n'est pas une
clear()
méthode réelle .la source
myqueue = { };
cela fonctionnera très bien.L'utilisation d'un
unique_ptr
peut être acceptable.Vous le réinitialisez ensuite pour obtenir une file d'attente vide et libérer la mémoire de la première file d'attente. Quant à la complexité? Je ne suis pas sûr - mais je suppose que c'est O (1).
Code possible:
la source
Une autre option consiste à utiliser un simple hack pour obtenir le conteneur sous-jacent
std::queue::c
et l'appelerclear
. Ce membre doit être présentstd::queue
conformément à la norme, mais l'est malheureusementprotected
. Le hack ici a été tiré de cette réponse .la source