Home > Articles > Programming > C/C++

  • Print
  • + Share This
Like this article? We recommend

Like this article? We recommend

A C++ Exception with No Handler

A C++ Exception with No Handler

Now say we want to see what happens if a C++ program throws an exception during its invocation. To demonstrate this possibility in Listing 8, let's reuse the C++ code from Listing 6. To make it a little more interesting (well, I think it's interesting, anyway <g>), I'll refactor the C++ code as the function callADynamicAllocation().

Listing 8—A C++ exception handler in action.

void callADynamicAllocation()
{
    int* myarray = NULL;
    if(myarray){
        cout << "Not NULL" << endl;
    }else{
        cout << "Is NULL" << endl;
    }
    try {
        int *myarray = new int[1000000000];
        std::cout << "Calling typeid: " << typeid (myarray).name() << std::endl;
    }
    catch(exception & e){
        cout << "Standard exception: " << e.what() << endl;
        if(myarray){
            cout << "Not NULL" << endl;
        }else{
            cout << "Is NULL" << endl;
        }
    }
    if(myarray){
        cout << "Deleting myarray" << endl;
        delete [] myarray;
    }
    cout << "Returning" << endl;
}

int main () {
    callADynamicAllocation();

    return 0;
}

Just to show I'm not cheating, Listing 9 shows the output from the refactored C++ program.

Listing 9—A C++ exception handler in action—same output as in Listing 7.

Is NULL
Standard exception: std::bad_alloc
Is NULL
Returning

No surprises in running the C++ code—it catches the exception. To make it more fun, let's add a new function with the same code, but without the exception handler code, producing Listing 10.

Listing 10—A C++ exception handler in action, and the same code with no handler.

void callADynamicAllocation()
{
    int* myarray = NULL;
    if(myarray){
        cout << "Not NULL" << endl;
    }else{
        cout << "Is NULL" << endl;
    }
    try {
        int *myarray = new int[1000000000];
        std::cout << "Calling typeid: " << typeid (myarray).name() << std::endl;
    }
    catch(exception & e){
        cout << "Standard exception: " << e.what() << endl;
        if(myarray){
            cout << "Not NULL" << endl;
        }else{
            cout << "Is NULL" << endl;
        }
    }
    if(myarray){
        cout << "Deleting myarray" << endl;
        delete [] myarray;
    }
    cout << "Returning" << endl;
}

void callADynamicAllocationNoExceptionHandler()
{
    int *myarray = new int[1000000000];
    std::cout << "Calling typeid: " << typeid (myarray).name() << std::endl;

    if(myarray) {
        cout << "Deleting myarray" << endl;
        delete [] myarray;
    }
    cout << "Returning" << endl;
}

int main () {
    callADynamicAllocationNoExceptionHandler();

    return 0;
}

When I run the code in Listing 10, here's what happens:

terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Notice in Listing 10 that we get unceremoniously dumped out of the program during the call to callADynamicAllocationNoExceptionHandler(). The runtime system detects the exception and reports it, but our code gets no opportunity at all to clean up, which could leave things in a nasty state; for example, with files open and/or partially updated, memory allocated, and so on. That's why it's a good idea to implement an exception handler.

Leaving out exception management in this case is a kind of anti-pattern. In this case, the separation of concerns we've used implicitly leaves exception handling up to the runtime system—the "higher calling code." It's the latter that must try to recover from the exception.

  • + Share This
  • 🔖 Save To Your Account