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:
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.
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, i.e. 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 (i.e. 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.