Bug 55841 - Unexpected behavior from STL's queue
Summary: Unexpected behavior from STL's queue
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.7.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-01-01 15:04 UTC by Nadav Har'El
Modified: 2013-01-01 21:16 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nadav Har'El 2013-01-01 15:04:02 UTC
Apparently, when a std::queue is empty, front() returns some bizarre output (a zeroed object?), and pop() breaks the queue by making its size -1... For example, this code, which pushes only one object on the queue, and pops 3, gives the following output::

#include <queue>
#include <iostream>
main(){
        std::queue<int> q;
        q.push(2);
        std::cerr << "size: " << q.size() << '\n';
        std::cerr << "popping element: " << q.front() << '\n';
        q.pop();
        std::cerr << "size: " << q.size() << '\n';
        std::cerr << "popping element: " << q.front() << '\n';
        q.pop();
        std::cerr << "size: " << q.size() << '\n';
        std::cerr << "popping element: " << q.front() << '\n';
        q.pop();
}

Gives the following output:

size: 1
popping element: 2
size: 0
popping element: 0
size: 18446744073709551615
popping element: 0

Why doesn't front() throw an exception when there's no element?
And why does pop() break the queue?

If I understand correctly, the standard doesn't define what to do in this case (I don't understand why), but even so, libstdc++ can do something sensible in this case...

Sure, I can always check empty() before calling front() or pop(), but isn't that very anti-C++-like, as exceptions were invented exactly so that code doesn't need to be littered with sanity checks like this, and rare cases of insanity cause exceptions?
Comment 1 Chris Jefferson 2013-01-01 20:21:13 UTC
I agree this behaviour might be annoying, but but there is no chance of it being changed, for efficency reasons. You will hey the same behaviour on all standard containers. 

For debugging purposes, look at the libstdc++ debugging mode, which will catch these types of errors. However, I would not recommend using debug mode in released applications.
Comment 2 Jonathan Wakely 2013-01-01 21:16:16 UTC
N.B. std::queue is a very thin adaptor (i.e. wrapper) around another container, the behaviour you are reporting is actually the behaviour of std::deque, not std::queue.


(In reply to comment #0)
> Apparently, when a std::queue is empty, front() returns some bizarre output

Assuming you're using std::deque as the queue's container_type, it is undefined behaviour to call front() when it is empty, so any result is allowed.

> Why doesn't front() throw an exception when there's no element?

It would be slower to check it on every use.  If I push one hundred elements into the container then call pop() one hundred times there would be one hundred useless checks that I don't want.

If you are not sure if it's safe to call pop() in your program then you should do the check in your own code, not force all users to pay for the checking on every call in every program.

> And why does pop() break the queue?

Because calling pop() on an empty sequence is undefined behaviour.

> If I understand correctly, the standard doesn't define what to do in this case
> (I don't understand why), but even so, libstdc++ can do something sensible in
> this case...

As Chris said, use the debug mode.

Or write your own wrapper around std::deque that adds checking and then use that as the container_type for std::queue.

> Sure, I can always check empty() before calling front() or pop(), but isn't
> that very anti-C++-like, as exceptions were invented exactly so that code
> doesn't need to be littered with sanity checks like this, and rare cases of
> insanity cause exceptions?

No, it's more C++-like to not pay for features you don't use. If I don't need to check the size on every call I shouldn't have to pay for that check.  If you need to check it you should pay for the checking, by adding it yourself.