FAQ 2.23 What are the basics of throwing and catching exceptions?

graphics/new_icon.gif

Exceptions are for handling errors. If a function cannot fulfill its promises for some reason, it should throw an exception. This style of reporting errors is different from the way many other programming languages report errors many languages use a return code or error code that the caller is supposed to explicitly test. It sometimes takes a little while before new C++ programmers become comfortable with the C++ way of reporting errors.

In the example code, function processFile() is supposed to process the specified file. The file name is specified using an object of the standard string class. If the file name is not valid (for example, if it contains illegal characters) or if the file does not exist, processFile() cannot proceed, so it throws an exception. In the case of an invalid file name, processFile() throws an object of class BadFileName; in the case of a nonexistent file, it throws an object of class FileNotFound.

Functions isValidFileName() and fileExists() represent routines that determine if a given file name is valid and exists, respectively. As shown below, isValidFileName() always returns true (meaning "yes, the filename is valid") and fileExists() always returns false (meaning "no, the file does not exist"), but in practice these routines would make system calls to determine the proper result.

 #include <iostream> #include <string> using namespace std; class BadFilename { }; class FileNotFound { }; bool isValidFilename(const string& filename) throw() {   // Pretend this checks if filename is a valid filename   return true; } bool fileExists(const string& filename) throw() {   // Pretend this checks if filename exists as a file   return false; } void processFile(const string& filename) throw(BadFilename, FileNotFound) {   if (! isValidFilename(filename))     throw BadFilename();   if (! fileExists(filename))     throw FileNotFound();   // the filename is valid and exists; process the file:   // ... } void f(const string& filename) throw() {   try {     processFile(filename);     // ...   }   catch (BadFilename& e) {     cout << "Invalid file name: " << filename << "\n";   }   catch (FileNotFound& e) {     cout << "File not found: " << filename << "\n";   } } 

try and catch are keywords. The code within the block after the try keyword is executed first. In this case, f() calls processFile(). In a real application, processFile() often succeeds (that is, it often returns normally without throwing an exception), in which case the runtime system continues processing the code in the try block, then skips the catch blocks and proceeds normally. In the case when an exception is thrown, control immediately jumps to the matching catch block. If there is no matching catch block in the caller, control immediately jumps back to the matching catch block in the caller's caller, caller's caller's caller, and so on, until it reaches the catch (...) block in main(), shown below. catch (...) is a special catch-all block: it matches all possible exceptions.

 int main() {   try {     f("input-file.txt");     // ...   }   catch (...) {     cout << "Unknown exception!\n";   } } 

The throw() declarations after the signature of the various functions (e.g., throw() after the signature of function f() and throw(BadFilename, FileNotFound) after the signature of function processFile()) are the function's way of telling callers what it might throw. Functions that say throw() are effectively saying, "This function doesn't throw any exceptions." Functions that say throw(BadFilename, FileNotFound) are effectively saying, "This function might throw a BadFilename object or a FileNotFound object but nothing else."



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net