views:

211

answers:

7

In the course of asking about catching 'divide by 0' exception, I found that with C++, we can't do that. I mean, divide by 0 doesn't throw an std::exception.

Some of the hints that I found were I have to check the value, and throw the exception by self.

I say it's confusing, as I've thought that C++ adopted the exception idea in order to replace the 'good old C/UNIX report error by returning value method'.

Here are my questions

  • Q1 : Why C++ doesn't throw std::exception error for divide by 0? Is there any reason behind that?
  • Q2 : Normally, what error processing scheme the C++ users use? Always throw an error, and the exception is the divide by 0 error?
  • Q3 : In general, OOP languages prefer (or even enforce) using exception. Is this correct?
+1  A: 

Divide by zero is something you can test for before the calculating line, which could avoid wasted cycles if it's a complicated formula.

Emyr
Pretty much any exception can be tested. Exceptions solves the problem of having every function return wheather it succeeds, or an error code if it doesn't succed.
Viktor Sehr
While any exception can be reported as an error code instead (though you'd have to use a tls global variable to report failure of a constructor -- yuck), most exceptional conditions cannot be avoided by testing beforehand. In fact anything that depends on shared state (file system, page tables, etc.) requires an atomic error reporting capability, simply splicing a check in front won't provide any atomicity guarantee.
Ben Voigt
+7  A: 

C++ assumes you know what you're doing, doesn't pay for things you don't ask for, and makes no assumptions about the platforms it's intended for.

If you want to divide numbers, it would be quite inefficient to mandate the compiler check the denominator and throw before dividing. (We didn't ask it to do that.) So that option is out; we can't have this check on every division, and it's especially wasteful since most divisions are not by zero.

So, how can we just divide by zero and find out if it worked? Because C++ cannot assume anything about it's platform, it cannot assume there is a way to check the result, hardware-wise. That is to say, while many CPU's will jump to an interrupt of some sort when division by zero occurs, the C++ language cannot guarantee such a thing.

The only option then is to let the behavior be undefined. And that's exactly what you get: undefined behavior.


OOP languages might do something or another, it doesn't matter since OOP isn't well-defined and C++ isn't an OOP language anyway. In general, use the tool that's most appropriate. (Exceptions are for exceptional situations.)

GMan
+2  A: 

C++ is implemented on many different platforms and is designed to support high-performance applications. Allowing undefined behaviour means than not all uses of division need to be burdened by extra checking and a possible exception throw by the compiler. The compiler is allowed to implement the fastest translation of divide in machine code regardless of its behaviour on divide by zero.

As with performing any operation, it is the programmers responsibility to ensure that any pre-conditions are met. In the case of division, a programmer may know that the divisor cannot be zero (or very small) and may just use an assert; in other cases he might need to validate the input and throw an application specific exception if the conditions aren't met.

C++ isn't (just) an OO language and doesn't (in most cases) enforce the use of exceptions. It provides them as a tool for use where appropriate. There are other languages which force the use of exceptions to a much greater degree.

Charles Bailey
+1  A: 

1) Throwing exceptions is an expensive operation. The C++ philosophy is not to pay for what you don't use. If you want exceptions, you throw them yourself (or use libraries that do).

2) Never accept the divide by zero error. It depends on the situation, if you know the input will never be a 0 never check for it. If you are unsure, always check for it. Then either throw an exception, or swallow the error quietly. It is up to you.

3) Exception throwing, especially combined with RAII can make for truely elegant and beautiful code. This may not be acceptable in all situations. You may have 100% confidence in your inputs and wish for raw performance. If you are creating a DLL you do not really want to be throwing exceptions out of your api, but for a critically consistant statically linked library you would be advised to.

DanDan
+1 for pointing out the beauty of well-structured, RAII-conforming code. Java programmers seemed to completely miss the point of how exception-handling becomes graceful only when we conform to RAII: the finally block just makes a mess. Unfortunately this kind of elegant code is hard to find in the real world since there are few programmers and few libraries which strictly conform to RAII.
+1  A: 

C++ doesn't use a lot of good principles in some places in order to maintain compatibility with C code. Java and such has no such constraints, so they can do what they'd like.

In C++, always throw an exception. But, for something like divide by zero, you really should just check it yourself. It's not an exceptional circumstance, it's you failing to check yourself.

DeadMG
+1  A: 

About Q3 - exceptions are something which should occure exceptional :) So to avoid (which is possible with div0) is always better. Additionally to Emyr (who is right about "avoid wasted cycles for calculation") you should consider that throwing an exception means a lot of "internal work" since the context changes (you may leave loop, functions, instance methods....) and your "excpetion stack" has to be prepared.

So in general exception handling is "the common method" to handle exceptions. But it should not be a pattern to avoid "value checking".

if(!string.IsNullOrEmpty(....) ... is much better than try{ xx=MyMabeNullString.Length... } catch{ //errmess - I could have checked it before :) }

ManniAT
+1  A: 
Jerry Coffin