CS11 – Introduction to C++ Spring 2013-2014 Lecture 6How To Report Errors? ! C style of error reporting: return values " For C Standard Library/UNIX functions, 0 usually means success, < 0 means error " Same for Windows API (HRESULT data type) " Additional error details must be stored elsewhere ! Not very informative! " Not all errors have the same details ! Propagating internal errors is also not clean " Enclosing function must explicitly pass along error " May accidentally mangle useful error informationC++ Exception Handling ! A mechanism for handling errors at runtime ! Code that can detect a problem, but might not know how to handle it, can throw an exception. " The “exception” is a value describing what happened. ! Code that knows how to handle the problem catches the exception. " Could be the immediate caller of the function, but it doesn’t have to be. " Caught exception specifies what happened to cause the problem. ! Complementary to other error-handling approaches, e.g. assertions.Throwing Exceptions ! An exception is a value describing the error " Could be any object, or even a primitive! " Usually a specific class (or set of classes) is used for representing errors ! C++ Standard Library provides exception classes ! People often create their own, too " Exception’s type usually indicates the general kind of error ! Example: double computeValue(double x) { if (x < 3.0) throw invalid_argument("x must be >= 3.0"); return 0.5 * sqrt(x – 3.0); }Catching Exceptions ! To catch an exception, use a try-catch block double x; cout << "Enter value for x: "; cin >> x; try { double result = computeValue(x); cout << "Result is " << result << endl; } catch (invalid_argument) { cout << "An invalid value was entered." << endl; } " Code within try block might throw exceptions " Specify what kind of exception can be handled at start of catch blockUsing Caught Exceptions ! Can name the caught exception: double x; cout << "Enter value for x: "; cin >> x; try { double result = computeValue(x); cout << "Result is " << result << endl; } catch (invalid_argument &e) { cout << "Error: " << e.what() << endl; } " This is better – can pass details of error in the exception " All C++ standard exception classes have what() functionMore Exception Details try { double result = computeValue(x); cout << "Result is " << result << endl; } catch (invalid_argument &e) { cout << "Error: " << e.what() << endl; } ! If computeValue() throws, execution transfers immediately to catch handler " “Result is…” operation is skipped. ! Usual variable scoping rules apply to try and catch blocks " Scope of result is only within try block ! catch-block cannot refer to variables declared within try-block " Scope of e is only within catch blockCatching Multiple Exceptions ! Can specify multiple catch blocks after a single try block try { performTask(config); } catch (invalid_argument &ia) { // Invalid args. cout << ia.what() << endl; } catch (bad_alloc &ba) { // Out of memory. cout << "Ran out of memory." << endl; } catch (exception &e) { // Something else??? cout << "Caught another standard exception: " << e.what() << endl; } ! Order matters! First matching catch-block is chosen. ! Only one catch block is executed.Handlers that Throw ! catch blocks can also throw exceptions, if necessary try { runOperation(); } catch (ProcessingError &pe) { if (!recover()) throw FatalError("Couldn't recover!"); } catch (FatalError &fe) { // Called when runOperation() throws, but // not when a previous catch block throws. cerr << "Couldn't compute!" << endl; } ! If ProcessingError catch-block throws another exception, it propagates out of entire try/catch block " Only exceptions thrown within the try block are handledCatching Everything… ! To catch everything, use ... for the exception type try { doSomethingRisky(); } catch (...) { // Catches ANY kind of exception cout << "Hmm, caught something..." << endl; } ! Problem: no type information about the exception! " Limits its general usefulness ! Usually used when code needs to guarantee that no exceptions can escape from the try-block ! Also used in test code, for verifying exception-throwing behavior of functionsException Propagation Obj3D * findObject(int objID) { Obj3D *pObj = ... // Find the object if (pObj == 0) throw BadObjectID(objID); return pObj; } void rotateObject(int objID, float angle) { Matrix m; // This could throw, but let the exception propagate Obj3D *pObj = findObject(objID); m.setRotateX(angle); pObj->transform(m); } ! If findObject() throws an exception: " The function stops executing where the exception is thrown " Its local variables are cleaned up automaticallyException Propagation (2) Obj3D * findObject(int objID) { Obj3D *pObj = ... // Find the object if (pObj == 0) throw BadObjectID(objID); return pObj; } void rotateObject(int objID, float angle) { Matrix m; // This could throw, but let the exception propagate Obj3D *pObj = findObject(objID); m.setRotateX(angle); pObj->transform(m); } ! rotateObject() doesn’t try to catch any exceptions! " If findObject() throws, it will propagate out of rotateObject() " rotateObject() will also stop executing where exception occurs m’s destructor is called automatically when an exception is thrownExceptions and Functions ! If an exception is not caught within a function, that function terminates. " Local variables go out of scope… " They are cleaned up via destructor calls, as usual ! If the calling function doesn’t handle the exception, it also terminates. " …and so forth, all the way up the stack… " This is called “stack unwinding” ! If main() doesn’t handle the exception, the entire program terminates.Catching Exceptions ! Catch a reference to the exception " Exceptions are passed by-value if catch-block doesn’t use a reference try { riskyBusiness(); } catch (MyException e) { ... } " The exception is copied into e when it is caught " Using “MyException &e” passes the exception by reference ! Several other good reasons to catch by reference! " See More Effective C++, Item 13, for even more details…Exceptions and Destructors ! Arrays of objects: MyClass
View Full Document