Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ Timesaving Techniques (2005) [eng].pdf
Скачиваний:
65
Добавлен:
16.08.2013
Размер:
8.35 Mб
Скачать

53 Throwing, Catching,

and Re-throwing

Technique Exceptions

Save Time By

Understanding exception handling

Throwing and logging exceptions

Dealing with unhandled exceptions

Re-throwing exceptions

Understanding structured exception handling

C++’s exception handling ability is a feature that differentiates it from virtually all older programming systems. As with Java, C#, and other modern programming languages, C++ offers the ability to jump out

of the middle of a block of code when an exceptional event occurs.

The concept of an exception handling is really quite simple. In older programming languages, when errors occurred, an error code was sent to the calling application, which could — and often did — simply ignore it. Exception handling changes this. It forces the application developer to consider in advance what could go wrong in the lower-level code, and to provide routines to contend with any errors that crop up. Now when an error — that is, an exception — occurs, the program passes control to the appropriate predefined routine. Error handling ensures that errors aren’t ignored; they’re dealt with.

This technique takes a closer look at throwing and catching exceptions. First, we examine throwing an exception and logging it in a generic fashion. Logging errors is important because it allows you to provide a complete debugging log that can be used to see what went wrong when a problem occurs. This will save you time and effort in debugging your application, and results in better code for the end-user.

Throwing and Logging Exceptions

In order to best understand how to use exception handling in your own applications, let’s look at a simple example of throwing exceptions in which those exceptions are logged to an output error file that can be used for debugging purposes. To do this, we will need two different types of classes.

We need a class to hold the information about what went wrong. This class will contain the line number where the error occurred and information detailing the nature of the error.

We need a class that will manage the process of catching the exception and logging the information into an error log.

 

 

Throwing and Logging Exceptions

313

The following steps show you how this is done:

2. Type the code from Listing 53-1 into your file.

 

1. In the code editor of your choice, create a new

Better yet, copy the code from the source file on

this book’s companion Web site.

 

 

file to hold the code for the technique.

 

 

 

 

 

In this example, the file is named ch53.cpp,

 

 

 

although you can use whatever you choose. This

 

 

 

file will contain the source code for our classes.

 

 

 

LISTING 53-1: THE EXCEPTION HANDLING CLASSES

 

 

 

#include <iostream>

 

 

 

#include <string>

 

 

 

#include <fstream>

 

 

 

#include <stdio.h>

 

 

 

using namespace std;

 

 

 

class ExceptionClass

 

 

1

{

 

 

 

string _message;

 

 

 

string

_file;

 

 

 

long

_line;

 

 

 

public:

 

 

 

 

ExceptionClass(void)

{

_message = “Unknown Exception”;

}

ExceptionClass( const char *msg, const char *fileName, long lineNo )

{

_message

= msg;

_file

=

fileName;

_line

=

lineNo;

}

ExceptionClass( const ExceptionClass& aCopy )

{

_message

= aCopy._message;

_file

=

aCopy._file;

_line

=

aCopy._line;

}

void setMessage(const char *msg, const char *fileName, long lineNo )

{

_message

= msg;

_file

=

fileName;

_line

=

lineNo;

}

(continued)

314 Technique 53: Throwing, Catching, and Re-throwing Exceptions

LISTING 53-1 (continued)

virtual string Report(void) const

{

string out;

out = “Exception reported in file “; out += _file.c_str();

out += “ at line “; out += _line; return out;

}

virtual ostream& Report( ostream& out ) const

{

out << “Exception reported in file “ << _file.c_str() << “ at line “ << _line << endl; out << _message.c_str() << endl;

return out;

}

};

 

 

 

class ExceptionCatcher

 

2

{

 

 

private:

 

 

 

string

_message;

 

 

ofstream

_logFile;

 

 

string

_fileName;

 

 

public:

 

 

 

ExceptionCatcher( void )

{

string msg = “Startup”; LogMessage( msg );

}

ExceptionCatcher( const char *fileName ) : _logFile( fileName )

{

string msg = “Startup”; msg += “ [“;

msg += fileName; msg += “]”; LogMessage( msg );

}

ExceptionCatcher( const ExceptionCatcher& aCopy ) : _logFile ( aCopy._fileName.c_str() )

{

_fileName = aCopy._fileName; _message = aCopy._message; string msg = “Startup”;

msg += “ [“;

msg += _fileName; msg += “]”; LogMessage( msg );

Throwing and Logging Exceptions

315

}

ExceptionCatcher( const ExceptionClass& exception )

{

_message = exception.Report();

}

virtual ~ExceptionCatcher()

{

string msg = “Shutdown”; LogMessage( msg );

}

virtual void LogMessage( string msg )

{

if ( !_logFile.fail() )

_logFile << msg.c_str() << endl;

}

virtual void LogMessage( const ExceptionClass& exception )

{

if ( !_logFile.fail() )

{

exception.Report( _logFile );

}

}

};

void process_option( int x )

{

if ( x < 2 || x > 8 )

throw “Invalid Input to process_option”;

int z = 10 / x;

cout << “Properly processed option “ << x << endl;

}

int func1( int x) throw( ExceptionClass )

{

ExceptionClass ec; try

{

switch ( x )

{

case 0:

cout << “You selected the first option” << endl; break;

case 1:

cout << “You selected the second option” << endl; break;

case 2:

process_option( x );

(continued)

316

Technique 53: Throwing, Catching, and Re-throwing Exceptions

 

 

LISTING 53-1 (continued)

 

 

 

default:

 

 

 

ec.setMessage( “Invalid Option”, __FILE__, __LINE__ );

 

 

 

throw ec;

 

 

 

}

 

 

}

catch ( const char *msg )

 

 

 

 

 

 

{

 

 

 

string sErr = “Unknown Error: “;

 

 

 

sErr += msg;

 

 

 

ec.setMessage( sErr.c_str(), __FILE__, __LINE__ );

 

 

 

throw ec;

 

 

 

}

 

 

}

return 0;

 

 

 

 

 

int main(int argc, char **argv)

 

 

{

if ( argc < 2 )

 

 

 

 

 

 

{

 

 

 

cout << “Usage: ch6_9 <inputs>” << endl;

 

 

 

cout << “Where: inputs is a series of numbers” << endl;

 

 

 

return -1;

 

 

 

}

 

 

 

ExceptionCatcher catcher(“errors.log”);

 

 

 

// Process the inputs.

 

 

 

for ( int i=1; i<argc; ++i )

 

 

 

{

 

 

 

int iVal = atoi( argv[i] );

 

 

 

try

 

 

 

{

 

 

 

func1(iVal);

 

 

 

}

 

3

 

catch ( ExceptionClass& ec )

 

 

{

 

ec.Report( cout ); catcher.LogMessage( ec );

}

catch ( ... )

{

cout << “Caught an exception” << endl;

}

}

return 0;

}