相关文章推荐
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I went through this page but I am not able to get the reason for the same . There it is mentioned that

"it is more sensible for it to return no value at all and to require clients to use front() to inspect the value at the front of the queue"

But inspecting an element from front() also required that element to be copied in lvalue. For example in this code segment

std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);
/* here temporary will be created on RHS which will be assigned to
   result, and in case if returns by reference then result will be
   rendered invalid after pop operation */
result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();

on fifth line cout object first creates a copy of myqueue.front() then assigns that to result. So, whats the difference, pop function could have done the same thing.

Your link is to the STL documentation. But you are asking about the C++ standard library. Different things. – juanchopanza Jul 30, 2014 at 11:55 "But inspecting an element from front() also required that element to be copied in lvalue" - no it doesn't. front returns a reference, not a value. You can inspect the value it refers to without copying it. – Mike Seymour Jul 30, 2014 at 12:10 @KeminZhou the model you describe requires a copy. Maybe. If you want to multiplex consumption of the queue then yes, you must make a copy before releasing the lock on the queue. However, if you only care about separating input and output, then you don't need a lock to inspect the front. You could wait to lock until you are done consuming it and need to call pop(). If you use std::queue<T, std::list<T>> then there is no concern about the reference provided from front() being invalidated by a push(). But you must know your usage pattern and should document your constraints. – jwm Sep 14, 2018 at 20:23 the real reason: compilers used to suck. we didn't have move semantics, noexcept & copy-elision. now we do, and besides all the nonsense you can read below, we could have an API that does this correctly and safely, but it's too late to change... – Spongman May 11, 2021 at 20:06

It could indeed have done the same thing. The reason it didn't, is because a pop that returned the popped element is unsafe in the presence of exceptions (having to return by value and thus creating a copy).

Consider this scenario (with a naive/made up pop implementation, to ilustrate my point):

template<class T>
class queue {
    T* elements;
    std::size_t top_position;
    // stuff here
    T pop()
        auto x = elements[top_position];
        // TODO: call destructor for elements[top_position] here
        --top_position;  // alter queue state here
        return x;        // calls T(const T&) which may throw

If the copy constructor of T throws on return, you have already altered the state of the queue (top_position in my naive implementation) and the element is removed from the queue (and not returned). For all intents and purposes (no matter how you catch the exception in client code) the element at the top of the queue is lost.

This implementation is also inefficient in the case when you do not need the popped value (i.e. it creates a copy of the element that nobody will use).

This can be implemented safely and efficiently, with two separate operations (void pop and const T& front()).

C++11 note: if T has a cheap noexcept move-constructor (which is often the case for the kind of objects put in stacks) then returning by value is efficient and exception-safe. – Roman L Dec 12, 2014 at 22:08 @RomanL: If the suggestion is that the signature of the function should change depending on the type that is contianed in the stack... that would be surprising at the very least. I don't see a problem with the current implementation (for the single threaded case) and I see no point in complicating the specification and implementations. – David Rodríguez - dribeas Apr 3, 2015 at 21:23 @DavidRodríguez-dribeas: I'm not suggesting any changes, my point was that some of the mentioned drawbacks become less of an issue with C++11. – Roman L Jun 13, 2015 at 15:36 But why is it called pop? that is quite counter-intuitive. It could be named drop, and then it's clear for everyone that it doesn't pop the element, but drops it instead... – UeliDeSchwert Dec 18, 2017 at 8:59 @utnapistim: the de-facto "pop" operation has always been to take the top element from a stack and return it. When I first came across STL stacks I was surprised, to say the least, about pop not returning anything. See for example on wikipedia. – Cris Luengo Jan 20, 2018 at 19:50

One might wonder why pop() returns void, instead of value_type. That is, why must one use front() and pop() to examine and remove the element at the front of the queue, instead of combining the two in a single member function? In fact, there is a good reason for this design. If pop() returned the front element, it would have to return by value rather than by reference: return by reference would create a dangling pointer. Return by value, however, is inefficient: it involves at least one redundant copy constructor call. Since it is impossible for pop() to return a value in such a way as to be both efficient and correct, it is more sensible for it to return no value at all and to require clients to use front() to inspect the value at the front of the queue.

C++ is designed with efficiency in mind, over the number of lines of code the programmer has to write.

Perhaps, but the real reason is that it is impossible to implement an exception safe version (with the strong guarantee) for a version of pop which returns a value. – James Kanze Jul 30, 2014 at 12:35 The real reason is exception safety. There is no safe way to have a "transaction" with the stack (either the element stays on the stack, or it's returned to you) if pop returns and the act of returning can result in an exception. It would obviously have to remove the element before it returns it, and then if something throws the element might be irrevocably lost. – Jon Jul 30, 2014 at 11:45 Does this concern still apply with f.i. a noexcept move constructor? (Of course 0 copies are more efficient that two moves, but that could open the door for an exception safe, efficent combined front+pop) – peppe Jul 30, 2014 at 11:45 @peppe, you could return by value if you know the value_type has a nothrow move constructor, but the queue interface would then be different depending on what type of object you store in it, which would not be helpful. – Jonathan Wakely Jul 30, 2014 at 11:47 @peppe: That would be safe, but stack is a generic library class and therefore the more it has to assume about the element type the less useful it is. – Jon Jul 30, 2014 at 11:48 I know the STL wouldn't allow for that, but that means one can build his own queue class with blackjack and ^W^W^W with this feature :) – peppe Jul 30, 2014 at 11:52

Then the following code could crash, since the reference is not valid anymore:

int &result = myqueue.pop();
std::cout << result;

On the other hand, if it would return a value directly:

value_type pop();

Then you would need to do a copy for this code to work, which is less efficient:

int result = myqueue.pop();
std::cout << result;

Or, if you want the value in a variable, use a reference:

const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;

Next to that: the wording 'more sensible' is a subjective form of 'we looked into usage patterns and found more need for a split'. (Rest assured: the C++ language is not evolving lightly...)

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.

 
推荐文章