9

I have used in many places if...else statements, however I'm new to exception handling. What is the main difference among these two?

for eg:

 int *ptr = new (nothrow) int[1000];
 
 if (ptr == NULL) {
     // Handle error cases here...
 }

OR

  try
  {
    int* myarray= new int[1000];
  }
  catch (exception& e)
  {
    cout << "Standard exception: " << e.what() << endl; 
  }

So we are using here standard class for exception which has some in build function like e.what(). So it may be advantage. Other than that all other functionality handling we can do using if...else also. Is there any other merits in using exception handling?

user438383
  • 5,716
  • 8
  • 28
  • 43
Newbee
  • 3,231
  • 7
  • 42
  • 74
  • 1
    Look up what `new` does if it fails. – chris Aug 19 '13 at 06:39
  • The difference is one can catch an exception and the other one can't. If the `new` allocation throws, your first example will not handle anything, and the exception will propagate. – juanchopanza Aug 19 '13 at 06:39
  • 1
    I think the OP meant more in general 'when to use exceptions'. Which I'm 100% sure has been covered 100 times here yet I can find a proper duplicate. – stijn Aug 19 '13 at 06:42

5 Answers5

3

To collect what the comments say in an answer:

since the standardization in 1998, new does not return a null pointer at failure but throws an exception, namely std::bad_alloc. This is different to C's malloc and maybe to some early pre-standard implementations of C++, where new might have returned NULL as well (I don't know, tbh).

There is a possibility in C++, to get a nullpointer on allocation failure instead of an exception as well:

int *ptr = new(std::nothrow) int[1000];

So in short, the first code you have will not work as intended, as it is an attempt of C-style error handling in the presence of C++ exceptions. If allocation fails, the exception will be thrown, the if block will never be entered and the program probably will be terminated since you don't catch the bad_alloc.

There are lots of articles comparing general error handling with exceptions vs return codes, and it would go way to far trying to cover the topic here. Amongst the reasons for exceptions are

  • Function return types are not occupied by the error handling but can return real values - no "output" function parameters needed.
  • You do not need to handle the return of every single function call in every single function but can just catch the exception some levels up the call stack where you actually can handle the error
  • Exceptions can pass arbitraty information to the error handling site, as compared to one global errno variable and a single returned error code.
Christian Dean
  • 22,138
  • 7
  • 54
  • 87
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90
2

The main difference is that the version using exception handling at least might work, where the one using the if statement can't possibly work.

Your first snippet:

int *ptr = new int[1000];

 if (ptr == NULL) {
     // Handle error cases here...
 }

...seems to assume that new will return a null pointer in case of failure. While that was true at one time, it hasn't been in a long time. With any reasonably current compiler, the new has only two possibilities: succeed or throw. Therefore, your second version aligns with how C++ is supposed to work.

If you really want to use this style, you can rewrite the code to get it to return a null pointer in case of failure:

int *ptr = new(nothrow) int[1000];

if (ptr == NULL) {
     // Handle error cases here...
}

In most cases, you shouldn't be using new directly anyway -- you should really use std::vector<int> p(1000); and be done with it.

With that out of the way, I feel obliged to add that for an awful lot of code, it probably makes the most sense to do neither and simply assume that the memory allocation will succeed.

At one time (MS-DOS) it was fairly common for memory allocation to actually fail if you tried to allocate more memory than was available -- but that was a long time ago. Nowadays, things aren't so simple (as a rule). Current systems use virtual memory, which makes the situation much more complicated.

On Linux, what'll typically happen is that even the memory isn't really available, Linux will do what's called an "overdcommit". You'll still get a non-null pointer as if the allocation had succeeded -- but when you try to use the memory, bad things will happen. Specifically, Linux has what's called an "OOM Killer" that basically assumes that running out of memory is a sign of a bug, so if it happens, it tries to find the buggy program(s), and kills it/them. For most practical purpose, this means your program will probably be killed, and other (semi-arbitrarily chosen) ones may be as well.

Windows stays a little closer to the model C++ expects, so if (for example) your code were running on an unattended server, the allocation might actually fail. Long before it fails, however, it'll drag the rest of the machine to its knees, madly swapping in a doomed attempt at making the allocation succeed. If the user is actually operating the machine at the time, they'll typically either kill your program or else kill some others to free up enough memory for your code to get the requested memory fairly quickly.

In none of these cases is it particularly realistic to program against the assumption that an allocation can fail though. For most practical purposes, one of two things happens: either the allocation succeeds, or the program dies.

That leads back to the previous advice: in a typical case, you should generally just use std::vector, and assume your allocation will succeed. If you need to provide availability beyond that, you just about need to do it some other way (such as re-starting the process if it dies, preferably in a way that uses less memory).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
2

As already mentioned, your original if-else example would still throw an exception from C++98 onwards, though adding nothrow (as edited) should make it work as desired (return null, thus trigger if-statement).

Below I'll assume, for simplicity, that, for if-else to handle exceptions, we have functions returning false on exception.

Some advantages of exceptions above if-else, off the top of my head:

  • You know the type of the exception for logging / debugging / bug fixing

    Example:

    When a function throws an exception, you can, to a reasonable extent, tell whether there may be a problem with the code or something that you can't do much about like an out of memory exception.

    With the if-else, when a function returns false, you have no idea what happened in that function.

    You can of course have separate logging to record this information, but why not just return an exception with the exception details included instead?

  • You needn't have a mess of if-else conditions to propagate the exception to the calling function

    Example: (comments included to indicate behaviour)

    bool someFunction() // may return false on exception
    {
       if (someFunction2()) // may return false on exception
          return false;
    
       if (someFunction3()) // may return false on exception
          return false;
    
       return someFunction4(); // may return false on exception
    }
    

    (There are many people who don't like having functions with multiple return statements. In this case, you'll have an even messier function.)

    As opposed to:

    void someFunction() // may throw exception
    {
       someFunction2(); // may throw exception
       someFunction3(); // may throw exception
       someFunction4(); // may throw exception
    }
    

An alternative to, or extension of, if-else is error codes. For this, the second point will remain. See this for more on the comparison between that and exceptions.

Community
  • 1
  • 1
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
1

If you handle the error locally, if ... else is cleaner. If the function where the error occurs doesn't handle the error, then throw an exception to pass off to someone higher in the call chain.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

First of all your first code with if statement will terminate program in case of exception thrown by new[] operator because of not handled exception. You can check such thing here for example: http://www.cplusplus.com/reference/new/operator%20new%5B%5D/

Also exceptions are thrown in many other cases, not only when allocation failed and their main feature (in my eyes) is moving control in application up (to place where exception is handled). I recommend you read some more about exceptions, good read would be "More Effective C++" by Scott Meyers, there is great chapter on exceptions.

Dino
  • 599
  • 1
  • 9
  • 20