简体   繁体   中英

C++ STL stack question: Why does pop() not throw an exception if the stack is empty?

Why does std::stack::pop() not throw an exception if the stack is empty and there is nothing to pop?

(I'm designing a specialized Stack for my own code and would like to know the tradeoffs with this approach (which requires one to manually check if the stack is empty) vs. throwing an exception.

My guess here would be that although C++ supports exception-handling, it comes with a small runtime overhead, and therefore, for maximum performance, the decision was made not to throw an exception in std::stack::pop).

I would argue that the reason pop() doesn't have to throw an exception has nothing to do with efficiency or performance, but with - exceptions.

As is argued elsewhere :

  1. SGI explanation: http://www.sgi.com/tech/stl/stack.html One might wonder why pop() returns void, instead of value_type. That is, why must one use top() and pop() to examine and remove the top element, instead of combining the two in a single member function? In fact, there is a good reason for this design. If pop() returned the top 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 top() to inspect the value at the top of the stack.

  2. std::stack < T > is a template. If pop() returned the top element, it would have to return by value rather than by reference as per the of above explanation. That means, at the caller side it must be copied in an another T type of object. That involves a copy constructor or copy assignment operator call. What if this type T is sophisticated enough and it throws an exception during copy construction or copy assignment? In that case, the rvalue, ie the stack top (returned by value) is simply lost and there is no other way to retrieve it from the stack as the stack's pop operation is successfully completed!

Once we conclude that pop should not return the element it pops and thus its interface is fixed as void pop() , it - this being my opinion - doesn't make any sense anymore to prescribe what happens when pop() is called on an empty stack.

Note that the standard requires !empty() as precondition for calling pop().

UncleBens (in the comments) certainly has a point that not checking preconditions at runtime (which is never prescribed by the C++ std AFAIK) has a certain performance smell to it. However, to quote part of the original question: (emphasis mine)

(I'm designing a specialized Stack for my own code and would like to know the tradeoffs with this approach (which requires one to manually check if the stack is empty ) vs. throwing an exception.

I will argue, that the fact that pop() doesn't return anything renders the question moot. It (IMHO) simply doesn't make sense to force pop() to validate if the stack is empty, when we really don't get anything back from it (ie if the stack would be empty pop() can simply be a noop, which is (admittedly) not prescribed by the Std either).

I think one can either ask why top() does not throw an exception or one can ask why pop() doesn't return the top element. If pop doesn't return anything, throwing an exception doesn't make sense (in the C++ world) -- Claiming that it doesn't throw an exception "because of the runtime costs of exceptions" like other answers seem to imply is - IMHO - missing the point.

You are correct. The C++ standard always prefers performance to safety. But there may be STL implementations that include debug range checks.

As almost all features in C++, they are designed around the concept that you don't pay for what you don't use. Not all environments support exceptions, traditionally, and most notably game development.

So forcing the use of exceptions if you use std::stack would be failing one of the design guidelines. You want to be able to use stack even if exceptions are disabled.

I think it's worth mentioning that pop() is allowed to throw if the stack is empty -- it's just not required to. In your stack, you could assert that the stack wasn't empty, and that would be perfectly fine ( pop on an empty stack seems to give UB, so you can do pretty much whatever you want, really).

除了性能之外,我不认为从空堆栈中弹出是一种特殊情况 - 因此我也不会抛弃它。

exceptions are optional, and the STL wants to be available everywhere. think embedded systems: lots of C++ code, no exception support from runtimes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM