Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Why does std::stack::pop() not throw an exception if the stack is empty?

Reply
Thread Tools

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

 
 
Debajit Adhikary
Guest
Posts: n/a
 
      02-03-2011
Why does std::stack:op() 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:op).
 
Reply With Quote
 
 
 
 
Joshua Maurice
Guest
Posts: n/a
 
      02-04-2011
On Feb 3, 1:51*pm, Debajit Adhikary <(E-Mail Removed)> wrote:
> Why does std::stack:op() 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:op).


You could be right under a very particular interpretation of your
words. Allow me to clarify, to ensure we're on the same page.

It's quite possible to implement exceptions so that the following two
programs will have basically the same runtime when passed no (command
line) arguments.
//program 1
int main(int argc, char** argv)
{ return (argc == 3) ? 1 : 0;
}
//program 2
int main(int argc, char** argv)
{ try
{ if (argc == 3)
throw 1;
}catch (int )
{ return 1;
}
return 0;
}

Let me emphasis that this is quite possible. A standard modern linux
and gcc distro on X86_64 has this behavior. Now, on the codepath where
argc == 3, then the first program is likely much faster than the
second. This is what most people say when they're talking about
"exception overhead", that is the overhead of having a possible throw,
but not actually executing it. To repeat, on a good implementation
like gcc on linux, if you don't throw, you don't pay a penalty.

On windows (32 and 64) and some other platforms, the situation is
different. Sadly, the compiler writers and ABI writers for those
platforms entirely missed the memo on how exceptions ought to be
implemented, and as such, you will see a measurable difference between
the runtime for programs like the above. Obviously not just for one
iteration, but if you have a program on windows that has possible
throw statements which are never executed, you can get measurably
faster code if you change the throws to return codes. Sad but true.

So, with that out of the way, there's one more issue to deal with. Why
does pop not throw an exception? Because even on the "ideal"
implementation of gcc on linux, there is still overhead to throw
because you must check the condition. The exception part is just a red
herring. The answer is the same even if you asked "Why doesn't pop
return an error code when the stack is empty?". Internally, it has to
have code like:
void stack:op()
{ if (is_empty())
throw something;
do_pop();
}
The execution of "is_empty()" on every pop is likely unnecessary for a
large majority of code, but it takes cycles even if it's not
necessary. The exception vs return code overhead discussion is
entirely irrelevant. It's a discussion of whether it's worth it to
check preconditions or call it UB. The C++ standard philosophy is to
only pay for what you use, and to provide building blocks for
developers. If the developer want to use a stack which has pop throw
on an empty stack, they're welcome to wrap std::stack. However, if it
was the reverse, you couldn't wrap std::stack and get rid of the
"is_empty()" check if it was inside std::stack:op, which is exactly
why it's not there.

PS: There is actual overhead for exceptions even on the ideal
implementation. The overhead is not execution time, but size. That
overhead is size of executable, and size of virtual, not resident,
memory. Those exception handlers have to go somewhere. If you have
virtual memory, it's almost a non-issue for a good implementation - if
you don't throw an exception, then the exception handlers never get
loaded to main memory, and it's almost as if they didn't even exist.
However, for platforms without virtual memory, such as some embedded
platforms, that memory overhead may be unacceptable.
 
Reply With Quote
 
 
 
 
Paul
Guest
Posts: n/a
 
      02-04-2011

"Joshua Maurice" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...

>The execution of "is_empty()" on every pop is likely unnecessary for a
>large majority of code, but it takes cycles even if it's not
>necessary.


Surely this condition must be tested before pop() deletes the object and
decrements the stack , anyway?



 
Reply With Quote
 
Andre Kaufmann
Guest
Posts: n/a
 
      02-04-2011
On 04.02.2011 01:12, Joshua Maurice wrote:
> On Feb 3, 1:51 pm, Debajit Adhikary<(E-Mail Removed)> wrote:
>> Why does std::stack:op() not throw an exception if the stack is empty and there is nothing to pop?

> [...]
> On windows (32 and 64) and some other platforms, the situation is
> different. Sadly, the compiler writers and ABI writers for those


The truth is: 32 bit Windows had to respect binary compatibility, while
under Linux the binary compatibility is not relevant.

I think for that reason 32 bit exception handling wasn't changed, when
the new exception handling mechanisms, which are quite more effective,
had been developed.

64 bit Windows exception handling (and the compiler generated code - VS
C++) is quite different to the 32 bit one and the implementation should
have the same low/none runtime overhead as under Linux.


Andre
 
Reply With Quote
 
Joshua Maurice
Guest
Posts: n/a
 
      02-04-2011
On Feb 3, 10:21*pm, Andre Kaufmann <(E-Mail Removed)> wrote:
> On 04.02.2011 01:12, Joshua Maurice wrote:
>
> > On Feb 3, 1:51 pm, Debajit Adhikary<(E-Mail Removed)> *wrote:
> >> Why does std::stack:op() not throw an exception if the stack is empty and there is nothing to pop?

> > [...]
> > On windows (32 and 64) and some other platforms, the situation is
> > different. Sadly, the compiler writers and ABI writers for those

>
> The truth is: 32 bit Windows had to respect binary compatibility, while
> under Linux the binary compatibility is not relevant.
>
> I think for that reason 32 bit exception handling wasn't changed, when
> the new exception handling mechanisms, which are quite more effective,
> had been developed.


Indeed.

But, well, there's no reason they had to piggyback C++ exception
handling on top of SEH. Is there? Would it have been reasonable to
extend the ABI to have SEH and C++ exceptions as different things?

> 64 bit Windows exception handling (and the compiler generated code - VS
> C++) is quite different to the 32 bit one and the implementation should
> have the same low/none runtime overhead as under Linux.


Last I tested, there's still a measurable overhead, whereas with gcc
on linux there is no measurable overhead.
 
Reply With Quote
 
Goran
Guest
Posts: n/a
 
      02-04-2011
On Feb 3, 10:51*pm, Debajit Adhikary <(E-Mail Removed)> wrote:
> Why does std::stack:op() 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:op).


My 2c: pop is a cleanup operation, and as such, it should have a
nothrow exception safety guarantee.

It's kinda like calling delete (or free) on a NULL pointer: it does
squat, but alternative of reporting an error seems worse.

Goran.
 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      02-04-2011
On 4 fév, 08:40, Goran <(E-Mail Removed)> wrote:
> On Feb 3, 10:51*pm, Debajit Adhikary <(E-Mail Removed)> wrote:
>
> > Why does std::stack:op() 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:op).

>
> My 2c: pop is a cleanup operation, and as such, it should have a
> nothrow exception safety guarantee.


It calls the destructor of contained object; a nothrow guarantee would
mean that you silently discard exceptions thrown from the object's
destructor. Not what you generally want.

> It's kinda like calling delete (or free) on a NULL pointer: it does
> squat, but alternative of reporting an error seems worse.


There is sure a tension between robustness and correctness but in
this case, IMO considering that deleting a NULL pointer is an error is
a bit to much. Being NULL is after all a valid state for a pointer.

--
Michael
 
Reply With Quote
 
Michael Doubez
Guest
Posts: n/a
 
      02-04-2011
On 3 fév, 22:51, Debajit Adhikary <(E-Mail Removed)> wrote:
> Why does std::stack:op() not throw an exception if the stack is empty and there is nothing to pop?


Because of 23.1/10 of the standard:
no erase(), pop_back() or pop_front() function throws an exception.

Erasing an element that doesn't exists or popping and empty container
is in itself not an error (just like emptying an empty bin). If your
logic requires to pop only non empty container, the requirement is at
your level, not at the level of the container (unless the underlying
container requires it).


> (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:op).


I don't think so. pop() can throw an exception from the underlying
container or the contained element's destructor. IMO the decision was
purely a matter of preferring robustness. An other alternative would
have to make this UB.

--
Michael
 
Reply With Quote
 
Paul
Guest
Posts: n/a
 
      02-04-2011

"Michael Doubez" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
On 4 fév, 08:40, Goran <(E-Mail Removed)> wrote:
> On Feb 3, 10:51 pm, Debajit Adhikary <(E-Mail Removed)> wrote:
>
> > Why does std::stack:op() 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:op).

>
> My 2c: pop is a cleanup operation, and as such, it should have a
> nothrow exception safety guarantee.


It calls the destructor of contained object; a nothrow guarantee would
mean that you silently discard exceptions thrown from the object's
destructor. Not what you generally want.

> It's kinda like calling delete (or free) on a NULL pointer: it does
> squat, but alternative of reporting an error seems worse.


There is sure a tension between robustness and correctness but in
this case, IMO considering that deleting a NULL pointer is an error is
a bit to much. Being NULL is after all a valid state for a pointer.

.................................................. ................................

Is it guaranteed delete will be called on a NULL pointer?

What happens if you do:

stack<int> x; //Internal pointer may be initialised to NULL
x.push(4); //Is pointer still NULL?
x.pop(); //What is pointer value now, is it guaranteed to be NULL?
x.pop(); //?

As it is undefined behaviour to call pop on an empty stack, then it's not
good practise to do this.













 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      02-04-2011
Michael Doubez <(E-Mail Removed)> wrote:
> I don't think so. pop() can throw an exception from the underlying
> container or the contained element's destructor.


Isn't it a kind of hard rule that destructors must never throw?

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
poping empty stack in visual c++ express - doesn't throw exception ? KRUNOPOPOVIC@YAHOO.COM C++ 11 03-05-2007 11:36 PM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
JNI's throw new does not throw an exception yarona@m-sys.com Java 15 09-08-2005 08:36 AM
Try-catch not working - why does this throw an Exception? Jon Maz ASP .Net 7 10-25-2004 04:55 PM
Throw Exception Vs Throw New Exception Kerri ASP .Net 2 10-27-2003 02:13 PM



Advertisments