Comment puis-je éliminer efficacement la file d'attente std::?

j'utilise std::queue pour implémenter la classe JobQueue. (Fondamentalement, cette classe traite chaque emploi de manière FIFO). Dans un scénario, je veux 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 mettre en œuvre efficacement la méthode clear pour la classe JobQueue ?

j'ai une solution simple de popping dans une boucle mais je suis à la recherche de meilleurs moyens.

//Clears the job queue
void JobQueue ::clearJobs()
 {
  // I want to avoid pop in a loop
    while (!m_Queue.empty())
    {
        m_Queue.pop();
    }
}
136
demandé sur aJ. 2009-04-02 14:16:13

10 réponses

un idiome courant pour le dédouanement des conteneurs standards est le remplacement d'une version vide du conteneur:

void clear( std::queue<int> &q )
{
   std::queue<int> empty;
   std::swap( q, empty );
}

c'est aussi le seul moyen de réellement vider la mémoire contenue dans certains conteneurs (std::vector)

212
répondu David Rodríguez - dribeas 2009-04-02 10:23:56

Oui - un peu de misfeature de la classe de file d'attente, à mon humble avis. C'est ce que je fais:

#include <queue>
using namespace std;;

int main() {
    queue <int> q1;
    // stuff
    q1 = queue<int>();  
}
37
répondu Mark Ransom 2013-04-29 21:18:49

de David Rodriguez', 'anon' L'auteur du sujet a demandé comment effacer la file "efficacement", donc je suppose qu'il veut une meilleure complexité que linéaire O(taille de la file). Les méthodes que vous avez servi la même complexité: selon la référence stl, opérateur = a une complexité O (taille de la file d'attente). IMHO c'est parce que chaque élément de la file d'attente est réservé séparément et il n'est pas alloué dans un grand bloc mémoire, comme dans vecteur. Donc, pour effacer toute mémoire, nous devons supprimer chaque élément séparément. De sorte que le la voie la plus directe pour libérer stl::queue est une ligne:

while(!Q.empty()) Q.pop();
17
répondu janis 2012-01-02 11:26:05

apparemment, il y a deux façons les plus évidentes d'effacer std::queue : l'échange avec un objet vide et l'affectation à un objet vide.

je suggérerais d'utiliser assignment parce qu'il est tout simplement plus rapide, plus lisible, et sans ambiguïté.

j'ai mesuré la performance en utilisant le code simple suivant et j'ai trouvé que l'échange dans la version c++03 Fonctionne 70-80% plus lent que l'affectation à un objet vide. En C++11, Il n'y a cependant pas de différence de performance. De toute façon, j'irais avec affectation.

#include <algorithm>
#include <ctime>
#include <iostream>
#include <queue>
#include <vector>

int main()
{
    std::cout << "Started" << std::endl;

    std::queue<int> q;

    for (int i = 0; i < 10000; ++i)
    {
        q.push(i);
    }

    std::vector<std::queue<int> > queues(10000, q);

    const std::clock_t begin = std::clock();

    for (std::vector<int>::size_type i = 0; i < queues.size(); ++i)
    {
        // OK in all versions
        queues[i] = std::queue<int>();

        // OK since C++11
        // std::queue<int>().swap(queues[i]);

        // OK before C++11 but slow
        // std::queue<int> empty;
        // std::swap(empty, queues[i]);
    }

    const double elapsed = double(clock() - begin) / CLOCKS_PER_SEC;

    std::cout << elapsed << std::endl;

    return 0;
}
11
répondu tim 2015-02-25 16:54:05

en C++11 Vous pouvez effacer la file d'attente en faisant ceci:

std::queue<int> queue;
// ...
queue = {};
4
répondu kolage 2018-07-13 14:43:25

vous pouvez créer une classe qui hérite de la file d'attente et effacer le conteneur sous-jacent directement. C'est très efficace.

template<class T>
class queue_clearable : public std::queue<T>
{
public:
    void clear()
    {
        c.clear();
    }
};

peut-être que votre implémentation A permet aussi à votre objet File d'attente (ici JobQueue ) d'hériter std::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() dans vos fonctions de membre.

2
répondu typ1232 2013-05-02 17:14:10

Je ne préfère pas utiliser swap() ou définir la file d'attente à un objet de file d'attente nouvellement créé, parce que les éléments de file d'attente ne sont pas correctement détruits. L'appel pop() invoque le destructeur pour l'objet de l'élément respectif. Cela pourrait ne pas être un problème dans les files d'attente <int> , mais pourrait très bien avoir des effets secondaires sur les files d'attente contenant des objets.

Donc 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 prévenir les effets secondaires possibles.

1
répondu Marste 2014-02-14 22:03:49

en supposant que votre m_Queue contient des entiers:

std::queue<int>().swap(m_Queue)

Sinon, si elle contient par exemple des pointeurs vers les objets Job , alors:

std::queue<Job*>().swap(m_Queue)

de cette façon , vous échangez une file d'attente vide avec votre m_Queue , donc m_Queue devient vide.

1
répondu Dániel László Kovács 2018-07-26 09:53:49

en utilisant un unique_ptr pourrait être OK.

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 suppose que c'est O(1).

Code Possible:

typedef queue<int> quint;

unique_ptr<quint> p(new quint);

// ...

p.reset(new quint);  // the old queue has been destroyed and you start afresh with an empty queue
0
répondu Ronnie 2015-01-10 18:32:13

je fais ceci (en utilisant C++14):

std::queue<int> myqueue;
myqueue = decltype(myqueue){};

de cette façon est utile si vous avez un type de file d'attente non trivial pour lequel vous ne voulez pas construire un alias/typedef. Je m'assure toujours de laisser un commentaire autour de cet usage, cependant, pour expliquer aux programmeurs peu méfiants / de maintenance que ce n'est pas fou, et fait en lieu et place d'une méthode réelle clear() .

0
répondu void.pointer 2018-09-24 16:16:00