You clearly do not understand the value and place of exception mechanisms.
Seriously, please go and read some articles on the design of the C++ exception mechanism and tutorials on the proper use of that mechanism.
I don't care if you think I'm being a jerk. Do yourself the favor of relying on my expertise and learn about C++ exceptions for yourself.
The "which approach" discussion was useful and an important topic, but repeatedly suggesting that every function invocation would need be wrapped, even if the client code would probably fail to do that, with the exception mechanism method is pointless, wrong, and distracting.
Still, I hate to say "You are wrong; go do research." without context. Regardless of what you apparently think I respect you quite a lot. (It must be said though, I don't do "PC".) I'll go ahead and carefully respond to what you've asked, but at this point I doubt you'll read it.
My attitude is that you don't know how to properly use the exception mechanism that C++ exposes and that you need to dispose yourself of that ignorance.
Perhaps you need to smack yourself first and change your attitude towards me before we continue discussing this.
It isn't a big deal; no one knows everything, but you have many times on this forum called yourself a C++ programmer. To name yourself a C++ programmer and so fundamentally misunderstand the exception mechanism is a shame.
I wasn't being rude by the way. It, "smack that nonsense right out", is an expression.
This is the exact opposite of the reason exception mechanisms in any language exists. The exception mechanism exists solely to propagate an error with any relevant context to an appropriate handler; it does not replace one local branch mechanism with another.
As to the try / catch the point is if 99 times out of 100 no one is going to wrap it then why throw at all?
Indeed, to say that "99 times out of 100" you will wrap every function invocation with `try' and `catch' blocks is to completely circumvent the exception mechanism. To make this absolutely clear, you shouldn't use any exception mechanism in that fashion; such a design is fundamentally broken.
Furthermore, to ask "why throw at all" is horrifying; if you are going to wrap every function invocation you absolutely should not be using exceptions at all; you should not be catching anything because you should not be throwing anything if you are always going to handle the exception locally; you should be using other means to convey an error situation.
You did say that. You changed it in an edit. I started writing my reply before the edit only to be interrupted by life.
If you will read my post I said that all three options are perfectly valid in their own right and it eventually comes down to a design decision.
It doesn't really matter though; my suggestion to educate yourself about C++ exceptions remains. You don't know how to put them to their best use. I understand that. I suggest you now learn how to put them to their best use as soon as is possible. They are a great feature in almost every language where they exist. (I can't tell you how pleased I was that Python was getting some improvement in that area.)
That is more nonsense. Consider the examples from "The C++ Programming Language".
Doing the operation will yield the same result as not wrapping it in a try / catch.
Again, you absolutely should not be wrapping every function invocation with `try' and `catch' blocks.
Consider the recent thread where "DirectDraw" was discussed. Your understanding of the exception mechanism as evidenced by your statements in this thread puts you at the same level as the "DirectDraw" advocate. It isn't really a matter of "point of view"; it is that you are operating on very bad information.
The discussion of the options relating to error notification and propagation is an important one, but the fact that you don't understand the exception mechanism is a different thing entirely. I'm not saying that your opinions relating to "return value or no return value" and "do nothing or just crash" isn't worth discussing. Those are options worth consideration in any given situation. I'm saying that until you improve your understanding of exceptions your opinion of exception mechanism based method is irrelevant.
These are not mutually exclusive goals. They are, in fact, the same goal.
So if the client has to think about when to handle the exception could they also just think about how they are using the stack and not request it to pop when it was empty?
The exception mechanism says "Hey! You need to know that something bad happened!". If the client code only wraps the function invocation with paraphernalia to suppress the warning, the are breaking the logic of the system do to a fundamental misunderstanding of the exception mechanism.
It isn't a question of "If you don't catch this, I'll scream about it.". That sort of thinking is beyond foolish. It is a question of "If you don't handle the condition that resulted in this situation, I'll scream about it.". Yes, the exception mechanism does the screaming. Yes, a simple return value can do the screaming. Both of these situations tell the client code something about the situation. The return value approach must be processed locally with a branch of some sort. (Yes, even if the return value is checked only to short circuit the function the condition is being processed locally.) The exception mechanism propagates the error condition upwards, and in some cases sideways, until it finds a bit of code that can handle the situation appropriately. With the exception mechanism, the client code doesn't have to ask "Should I check this just to be sure it succeeded?" as it would be for the return value version; the client code can assume that the function invocation was successful otherwise processing would have "jumped" to the bit of code designed to handle that error condition.
In other words, your understanding of the exception mechanism is almost entirely backwards.
Though the advice is terse, I will offer you this bit of folkish wisdom: "Throw often; catch rarely.". As with any other advice, it can lead you wrong, but it is better than what you have.
This is all true, but, as with the template argument you used to bring up, framed partially of false information. I know that statement ........es you off, but, like it or not, you are not looking at the entire picture.
I'm also used to working in a DLL based environment where every piece and component is another DLL. Throwing across the DLL boundary is not a good idea if your component is going to be in the field for awhile which pretty much guarantees that the compiler used to build the DLL is not the same compiler used to build the client and thus could cause major issues.
The longevity of a component is irrelevant. Most everyone here would like "Turbo C" to die for good and yet it lingers.
Conventional wisdom of "Don't throw exceptions across library boundaries." wasn't formed because it is sound design advice. Unfortunately, the real world just gets in the way. Allowing exceptions to propagate across library boundaries in other languages is the usual approach. C++ developed that bit of advice because compilers just don't get along. (I know you know this part. We haven't got to the bit that makes this bit all but irrelevant in practice.) Unfortunately, it only tells half the story. Not only do compilers not agree on how to implement the exception mechanism; compiler venders can't even agree on class padding which is one of the most trivial components of user defined exceptions. Every experienced C++ programmer knows that "Visual C++" and "GCC" don't really get along, but that paring barely scratches the surface. In the real world you can't even guarantee that you'll be able to link against libraries compiled with a different version of the same compiler. That's the commercial ones! We have a few open source compilers. You can't even offer a reasonable guarantee that the same version of the same compiler itself built with the same flags for the same environment can link with C++ libraries because multiple times vendors have introduced strange default flags that break compatibility.
So, yea, you are absolutely correct; you can't trust an exception thrown across a library boundary to be useable by client code, but you are absolutely wrong to think that situation means a lot because the truth is the API exported by the library may not be useable by client code even without exceptions, even without templates, even without function overloads, even without default values, even without virtual function, even without inheritance, and even without "RTTI" because the C++ standard specifically allows compiler venders to choose their own "Application Binary Interface" which means that any expectations of formal compatibility goes right out the window. (It should be noted that the standard allows this by lots of "implementation defined" areas.)
Relying on an exception mechanism isn't a implementation detail. Seriously, again not being a jerk but it is fine if you think so, if you knew as much about exception mechanisms as I do you would know exactly what I'm talking about. The instant you say "Okay, the constructor for this class may throw an exception." you place requirements on the design, not the implementation, that would not exist otherwise.
It is my opinion that the design of something like this is far more important than the details of the implementation since the implementation is pretty straightforward.
If you could safely say "Compiler, I need you to enforce a "no exceptions" policy on everything I'm going to use in this function." you could do a lot better with the interface that what has been proposed; in such a world as that I would suggest something more "functional".
Granted, this can still be done, but if the underlying bits can't throw an exception when the preconditions are valid the above code can be trivially implemented in such a way that it literally can not fail. (Naturally, a rock could go through your window at exactly that moment and fault your processor.) "Can not fail." would be an amazingly wonderful property of a component.
For the return value, if the operation may fail and the client code wants to handle that error at any point in any conceivable way the client code has no choice but to check the return value each and every time.
When would the client wrap the pop() in a try / catch or in a conditional if there is the possibility the call could fail.
For the exception mechanism, if the operation may fail the client code can not recover from such an error locally the client code may safely ignore that possibility at that point in the code; the client code does not have to process the exception and can be written almost as if no error could occur while still providing a means of graceful recovery or at least an informative crash.
Look at the relevant bits from the source I posted. I checked the return value every time; I have to do that if I want deal with that error condition in a safe and graceful way. However, I only check for the error condition as an exception once because all of the errors related to "Insufficient Data: The expression being operated on was invalid." can be handled in that one place.
If there is the possibility the call could fail then should not the return value and/or the exception be checked for each time?
That is simply wrong; I'm not acting or saying anything that could possibly make you think that I'm implying magic or psychic client code.
You act as if the client code is going to magically know when the call could fail...or know when the stack is empty...and if they knew that....then why the heck would they call pop() in the first place?
That is very nearly the opposite of what I'm saying.
I've said, more than once, that with the return value method, if the client code might ever care about the error condition, the return value must be inspected at every function invocation. Manually coding multiple points of inspection is, in this context, as far from being magic as is possible.
I've also said that with the exception mechanism method the client code doesn't have to inspect the exception every invocation unless the error condition can be handled locally. That isn't magic; that is simply what an exception mechanism offers.