104

I need to iterate over std::queue. www.cplusplus.com says:

By default, if no container class is specified for a particular queue class, the standard container class template deque is used.

So can I somehow get to the queue's underlying deque and iterate over it?

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
jackhab
  • 17,128
  • 37
  • 99
  • 136

10 Answers10

90

If you need to iterate over a queue then you need something more than a queue. The point of the standard container adapters is to provide a minimal interface. If you need to do iteration as well, why not just use a deque (or list) instead?

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 161
    While I know what you're saying, I've always disliked this phrasing "something more than a queue". A queue with enumeration is still a queue... Also, observe how `deque` just happens to support enumeration, completely arbitrarily. You could just as well argue that `deque` should be just as purist as `queue` and not support iteration, and if you want to iterate it then you want something "more"; e.g. a `deque_enumerable`. It's a slippery slope though, and my personal feeling is that `queue` should have supported enumeration in the first place. – Roman Starkov May 31 '10 at 10:37
  • 10
    @romkyns: Would it be better if I rephrased it: "You need something with a richer interface than the `queue` interface so you should choose an object with a suitable interface". Like it or not, iteration isn't part of the `queue` interface so if you want iteration you need to choose something else. – CB Bailey May 31 '10 at 12:28
  • 21
    Because my use case requires a queue, but I need to dump it out for debug and logging purposes. It's generally not constructive to assume that posters don't know what they're doing. – EML Mar 02 '17 at 09:03
  • 7
    @RomanStarkov - Seems like it should have been possible for `queue` to support forward iterators but not reverse iterators without burdening any reasonable implementation I can think of. I guess CS101 profs might have complained about it... – T.E.D. Apr 13 '17 at 15:51
  • 1
    It's funny how by default `queue` uses `deque`. So if you replace `queue` with `deque` you would really have the exact same memory layout and would only need to replace `push` with `push_back` and `pop` with `pop_front` – Paul Stelian Nov 03 '18 at 12:37
  • 9
    @EML - My need exactly. Somehow debugging requirements are often neglected as something needed by fringe lunatics only – Waslap Apr 10 '19 at 07:42
43

While I agree with others that direct use of an iterable container is a preferred solution, I want to point out that the C++ standard guarantees enough support for a do-it-yourself solution in case you want it for whatever reason.

Namely, you can inherit from std::queue and use its protected member Container c; to access begin() and end() of the underlying container (provided that such methods exist there). Here is an example that works in VS 2010 and tested with ideone:

#include <queue>
#include <deque>
#include <iostream>

template<typename T, typename Container=std::deque<T> >
class iterable_queue : public std::queue<T,Container>
{
public:
    typedef typename Container::iterator iterator;
    typedef typename Container::const_iterator const_iterator;

    iterator begin() { return this->c.begin(); }
    iterator end() { return this->c.end(); }
    const_iterator begin() const { return this->c.begin(); }
    const_iterator end() const { return this->c.end(); }
};

int main() {
    iterable_queue<int> int_queue;
    for(int i=0; i<10; ++i)
        int_queue.push(i);
    for(auto it=int_queue.begin(); it!=int_queue.end();++it)
        std::cout << *it << "\n";
    return 0;
}
Alexey Kukanov
  • 12,479
  • 2
  • 36
  • 55
22

you can save the original queue to a temporary queue. Then you simply do your normal pop on the temporary queue to go through the original one, for example:

queue tmp_q = original_q; //copy the original queue to the temporary queue

while (!tmp_q.empty())
{
    q_element = tmp_q.front();
    std::cout << q_element <<"\n";
    tmp_q.pop();
} 

At the end, the tmp_q will be empty but the original queue is untouched.

Keerti Purswani
  • 4,878
  • 3
  • 16
  • 29
StupidMe
  • 223
  • 2
  • 5
6

One indirect solution can be to use std::deque instead. It supports all operations of queue and you can iterate over it just by using for(auto& x:qu). It's much more efficient than using a temporary copy of queue for iteration.

Tejas Patil
  • 61
  • 1
  • 2
5

while Alexey Kukanov's answer may be more efficient, you can also iterate through a queue in a very natural manner, by popping each element from the front of the queue, then pushing it to the back:

#include <iostream>
#include <queue>

using namespace std;

int main() {
    //populate queue
    queue<int> q;
    for (int i = 0; i < 10; ++i) q.push(i);

    // iterate through queue
    for (size_t i = 0; i < q.size(); ++i) {
        int elem = std::move(q.front());
        q.pop();
        elem *= elem;
        q.push(std::move(elem));
    }

    //print queue
    while (!q.empty()) {
        cout << q.front() << ' ';
        q.pop();
    }
}

output:

0 1 4 9 16 25 36 49 64 81 
Vaelus
  • 1,065
  • 10
  • 27
2

Why not just make a copy of the queue that you want to iterate over, and remove items one at a time, printing them as you go? If you want to do more with the elements as you iterate, then a queue is the wrong data structure.

Chuck
  • 47
  • 1
  • 7
    Er, no. Copying then destroying a queue is way more overhead than you should need. This is why iterators were invented. – Mac Dec 04 '12 at 22:15
  • 1
    Simpler: Create empty queue. Pop each item off your main queue until empty, process it as desired, and push it onto the empty queue. When finished, set the main queue to equal the empty queue. Works for priority_queue as well. Caveat: Not thread-safe if some other thread is trying to access the queue at the same time. Also, if your original was heap-allocated (created via `malloc`/`new`), be sure to `free`/`delete` it or you'll leak memory. – Darrel Hoffman Oct 28 '15 at 21:16
  • -1: I am actually getting too low of a framerate for VERY small queues which I copy (I'm not getting 60FPS because of such copies every frame, with VERY few objects -- something that my GPU should be capable of 300+ FPS with VSync disabled). I need a way to iterate it without copying – Paul Stelian Nov 03 '18 at 12:39
0

In short: No.

There is a hack, use vector as underlaid container, so queue::front will return valid reference, convert it to pointer an iterate until <= queue::back

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Dewfy
  • 23,277
  • 13
  • 73
  • 121
  • 2
    You can also directly use deque - that contains all necessary methods as queue but also supports iteration – Dewfy Aug 11 '09 at 09:16
-1

std::queue is a container adaptor, and you can specify the container used (it defaults to use a deque). If you need functionality beyond that in the adaptor then just use a deque or another container directly.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • 5
    While your answer is correct, there was absolutely no need for it, since this 2 year old question already has two answers saying exactly the same (with one of them being the accepted answer). – Christian Rau Dec 04 '12 at 16:04
  • @ChristianRau Yes but this is the only answer that manages to pin point the **proximal cause** of confusion - that `queue` is a *container adapter* and not a *container*. Other answerers have focused too much on demonstrating knowledge and missed the teaching mark IMHO. – c z Feb 01 '23 at 17:17
-1

I use something like this. Not very sophisticated but should work.

    queue<int> tem; 

    while(!q1.empty()) // q1 is your initial queue. 
    {
        int u = q1.front(); 

        // do what you need to do with this value.  

        q1.pop(); 
        tem.push(u); 
    }


    while(!tem.empty())
    {
        int u = tem.front(); 
        tem.pop(); 
        q1.push(u); // putting it back in our original queue. 
    }

It will work because when you pop something from q1, and push it into tem, it becomes the first element of tem. So, in the end tem becomes a replica of q1.

shamiul97
  • 315
  • 1
  • 3
  • 13
  • This solution is very problematic since it modifies the queue during iteration. Just imagine what would happen if you use it in multi-threaded program or in case you stop iteration in the middle. – jackhab Nov 28 '18 at 12:11
  • @jackhab thanks. You are right. That could be a problem. But we could use semaphore or mutex to overcome that problem (as I am doing in my Operating System assignment of IPC and pthread). – shamiul97 Nov 28 '18 at 13:28
-2

If you need to iterate a queue ... queue isn't the container you need.
Why did you pick a queue?
Why don't you take a container that you can iterate over?


1.if you pick a queue then you say you want to wrap a container into a 'queue' interface: - front - back - push - pop - ...

if you also want to iterate, a queue has an incorrect interface. A queue is an adaptor that provides a restricted subset of the original container

2.The definition of a queue is a FIFO and by definition a FIFO is not iterable

TimW
  • 8,351
  • 1
  • 29
  • 33
  • 40
    I'm not the OP, but here are my answers, in case anyone is curious: 1) I picked a queue because I want a queue. I want to enqueue at one end and dequeue at the other. Is this not a reasonable choice? 2) It's not obvious that a "queue" is not enumerable, nor which structure to use instead. Your answer would have been more helpful if you explained which container to use instead. – Roman Starkov May 31 '10 at 10:50