views:

536

answers:

7
const int MIN_NUMBER = 4;
class Temp
{
public:

    Temp(int x) : X(x)
    {
    }

    bool getX() const
    {
     try
     {
      if( X < MIN_NUMBER)
      {
       //By mistake throwing any specific exception was missed out
       //Program terminated here
       throw ;
      }
     }
     catch (bool bTemp)
     {
      cout<<"catch(bool) exception";

     }
     catch(...)
     {
      cout<<"catch... exception";
     }
     return X;
    }

private:
    int X;
};



int main(int argc, char* argv[])
{
    Temp *pTemp = NULL;
    try
    {
     pTemp = new Temp(3);
     int nX = pTemp->getX();
     delete pTemp;
    }
    catch(...)
    {
     cout<<"cought exception";
    }

    cout<<"success";
    return 0;
}

In above code, throw false was intended in getX() method but due to a human error(!) false was missed out. The innocent looking code crashed the application.

My question is why does program gets terminated when we throw "nothing”?

I have little understanding that throw; is basically "rethrow" and must be used in exception handler (catch). Using this concept in any other place would results into program termination then why does compiler not raise flags during compilation?

A: 

You don't have anything to catch, and so the exception bubbles all the way up. Even catch(...) needs something.

Joel Coehoorn
Can not compiler find this error and raise flag?
aJ
I think he's asking why "throw;" is legal outside a catch block, not why it doesn't get caught.
jalf
@jalf: No, I think he's asking why it doesn't get caught. Which is addressed by Neil Butterworth's answer.
chaos
@aJ: the compiler cannot know at this time. You can create a function that rethrows the last exception caught and process it (we do it to centralize some of the CORBA exceptions). When compiling that function the compiler won't know if the caller has actually caught something or not.
David Rodríguez - dribeas
He asks both questions - why isn't it getting caught? and why doesn't the compiler complain that the rethrow isn't inside a catch?
Michael Burr
+22  A: 

This is expected behaviour. From the C++ standard:

If no exception is presently being handled, executing a throw-expression with no operand calls terminate()(15.5.1).

As to why the compiler can't diagnose this, it would take some pretty sophisticated flow analysis to do so and I guess the compiler writers would not judge it as cost-effective. C++ (and other languages) are full of possible errors that could in theory be caught by the compiler but in practice are not.

anon
This doesn't answer aJ's other question as to why 'throw;' is useful in the first place
Aaron
I am wondering why is it not possible for compiler to detect this?
aJ
I guess the compiler doesn't detect it because it's part of the C++ specification. Yes, it sucks - No, you shouldn't do it. That's C++ for ya - hate it or love it :)
cwap
This cannot be detected by the compiler because it involves runtime behaviour.
anon
Lets say I change the getX() to remove try-catch block: bool getX() const { if( X < MIN_NUMBER) { throw ; } return X; }
aJ
aJ, it doesn't matter. people can call the function from within a catch block and then throw ; is valid.
Johannes Schaub - litb
A: 

I have little understanding that throw; is basically "rethrow" and must be used in exception handler (catch). Using this concept in any other place would results into program termination then why does compiler not raise flags during compilation?

Rethrowing is useful. Suppose you have a call stack three levels deep with each level adding some context resource object for the final call. Now, when you have an exception at the leaf level, you will expect some cleanup operation for whatever resources the object has created. But this is not all, the callers above the leaf may also have allocated some resources which will need to be deallocated. How do you do that? You rethrow.

However, what you have is not rethrow. It is a signal of giving up after some failed attempts to catch and process any and all exceptions that were raised.

dirkgently
+10  A: 

From the C++ standard:

15.1 Throwing an exception

...

If no exception is presently being handled, executing a throw-exception with no operand calls terminate()

The reason the compiler can't reliably catch this type of error is that exception handlers can call functions/methods, so there's no way for the compiler to know whether the throw is occurring inside a catch. That's essentially a runtime thing.

Michael Burr
A: 

A throw inside of a catch block with no args will re-throw the same exception that was caught, so it will be caught at a higher level.

A throw outside of a catch block with no args will cause a program termination.

Brian R. Bondy
A: 

To complete the previous answers with an example of when/why the compiler cannot detect the problem:

// Centralized exception processing (if it makes sense)
void processException()
{
   try {
      throw;
   }
   catch ( std::exception const & e )
   {
      std::cout << "Caught std::exception: " << e.what() << std::endl;
   }
   catch ( ... )
   {
      std::cout << "Caught unknown exception" << std::endl;
   }
}

int main()
{
   try
   {
      throw 1;
   }
   catch (...)
   {
      processException(); // correct, still in the catch clause
   }
   processException(); // terminate() no alive exception at the time of throw.
}

When compiling the function processException the compiler cannot know how and when it will be called.

David Rodríguez - dribeas
+7  A: 

To elaborate on Neil's answer:

throw; by itself will attempt to re-raise the current exception being unwind -- if multiple are being unwound, it attempts to rethrow the most recent one. If none are being unwound, then terminate() is called to signal your program did something bogus.

As to your next question, why the compiler doesn't warn with throw; outside a catch block, is that the compiler can't tell at compile-time whether the throw; line may be executing in the context of a catch block. Consider:

// you can try executing this code on [http://codepad.org/pZv9VgiX][1]
#include <iostream>
using namespace std;

void f() {
    throw 1;
}
void g() {
    // will look at int and char exceptions
    try { 
        throw;
    } catch (int xyz){
        cout << "caught int " << xyz << "\n";
    } catch (char xyz){
        cout << "caught char " << xyz << "\n";
    }
}
void h() {
    try {
        f();
    } catch (...) {
        // use g as a common exception filter
        g();
    }
}
int main(){
    try {
        h();
    } catch (...) {
        cout << "some other exception.\n";
    }
}

In this program, g() operates as an exception filter, and can be used from h() and any other function that could use this exception handling behavior. You can even imagine more complicated cases:

void attempt_recovery() {
    try{
        // do stuff
        return;

    } catch (...) {}

    // throw original exception cause
    throw;
}
void do_something() {
    for(;;) {
        try {
            // do stuff
        } catch (...) {
            attempt_recovery();
        }
    }
}

Here, if an exception occurs in do_something, the recovery code will be invoked. If that recovery code succeeds, the original exception is forgotten and the task is re-attempted. If the recovery code fails, that failure is ignored and the previous failure is re-throw. This works because the throw; in attempt_recovery is invoked in the context of do_something's catch block.

Aaron