Henry Wise
Henry Wise

Reputation: 395

Getting reference of the front element when queue is popped

I'm playing with some examples to decide whether it is safe to use the reference to the front of the queue when I know it is going to be popped later.

queue<int> q;
q.push(5);
q.push(2);
int & a = q.front(); // a = 5 now
q.pop();
q.push(123);
cout << a << "\n"; // a = 5 now

This example makes it look like it is safe.

queue<int> q;
q.push(5);
int & a = q.front(); // a = 5 now
q.pop();
q.push(123);
cout << a << "\n"; // a = 123 now

This example makes me realize I probably have to make a copy of the front element instead of using a reference. However, I do not understand the behavior discrepancy between the two examples. Shouldn't the second example variable "a" also be 5? Can someone explain it to me?

Upvotes: 1

Views: 1854

Answers (1)

dfrib
dfrib

Reputation: 73186

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.


As governed by [deque.modifiers]/4 [emphasis mine]:

iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
void pop_front();
void pop_back();

Effects: An erase operation that erases the last element of a deque invalidates only the past-the-end iterator and all iterators and references to the erased elements. An erase operation that erases the first element of a deque but not the last element invalidates only iterators and references to the erased elements. An erase operation that erases neither the first element nor the last element of a deque invalidates the past-the-end iterator and all iterators and references to all the elements of the deque. [ Note: pop_­front and pop_­back are erase operations.  — end note ]

The effects of invoking pop() on a std::queue object is as if invoking pop_front() on a std::deque object. Thus, storing a reference to the front() of a std::queue object, say stored as ref_front, followed by invocation of pop() on the queue object invalidates the ref_front reference.

queue<int> q;
q.push(5);
int & a = q.front();
q.pop();              // invalidates reference 'a'
// ... reading 'a' invokes undefined behaviour

Thus, both your examples invokes undefined behaviour, demons may fly out of your nose and any kind of analysis of your program beyond this point will be a fruitless exercise.

Upvotes: 3

Related Questions