Vault
4.1
|
Classes | |
class | VSystemError |
VSystemError captures the current system error code and the corresponding error message text. More... | |
class | VStackTraceException |
This simple helper class throws an exception with a stack trace included, without having to pass the boolean as you do with the base class. More... |
The Vault does not return error codes; instead it always throws exceptions of type VException or its subclass VEOFException. As is necessary for proper C++ behavior, these exceptions are always thrown "by value", and should be caught "by reference". For example:
When throwing, you can construct a VException with several different constructor forms, including hardcoded strings, sprintf-like syntax, etc., with or without integer error codes. For example:
When catching, you can get the error message as a (char*), and can get the integer error code. For example:
On Unix-based systems, when a function call fails you are often directed to check 'errno' (which is usually a macro for a thread-local stored error value) as an error code, and can call strerror(errno) to get a system error message string that describes the error code.
On Windows, the analog of errno and strerror() are GetLastError() (or for WinSock APIs, WSAGetLastError()) and a complicated API FormatMessage().
It's often desirable to throw a VException that contains the error code and system error message, along with a string that describes your operation that failed. To facilitate this in a cross-platform way, all of the VException classes have constructors that take a VSystemError object. You can supply such an object by calling one of two static functions of VSystemError -- getSystemError() and getSocketError(). For most errors use the former, and for socket API errors use the latter. The distinction is because on Windows there is a difference (internally there are two functions for getting error codes, one specific to sockets).
For example, if we fail to open a file successfully, we can write: throw VException(VSystemError(), VSTRING_FORMAT("Failed to open file '%s'.", path.chars())); Or if we fail on a socket connect() call, we can write: VSystemError e = VSystemError::getSocketError(); vault::closeSocket(socketID); throw VException(e, VSTRING_FORMAT("Failed to connect to '%s'.", ipAddress.chars()));
Note the second example above showing a situation where we need to put the VSystemError object into a local variable before throwing the exception, because we first close() the bad socket, and the act of calling close() means that presumably close() will succeed and thus set the system error code to 0. We need to "stash" the error code that happened on the connect() failure, because if we retrieve the socket error code as we construct the exception, we'll be retrieving the 0 value that resulted from a successful closeSocket() call.
The VException will be filled in with the error code, and the error message you supply will have the system error message (including the numeric value) appended. For example, in the above, the exceptions might contain these error strings: "Failed to open file 'foo'. Error 2: File not found." "Failed to connect to '1.2.3.4'. Error 51: Network is unreachable." The VException numeric error code values would be 2 and 51, respectively.
This style of building exceptions relieves you of having to worry about how to consistently retrieve and format the system level error codes and error messages. Just say what operation failed (with details as specific as you need, such as an item name/description and a function return code) and pass in the VSystemError object that is relevant.
VEOFException is thrown by the stream i/o classes when they unexpectedly encounter EOF during a read operation. (Of course, socket reads simply block if there is no data; an EOF exception would indicate that the socket has been closed and there really cannot be any more data to block on.) In some cases, you may want to use this as a "normal" signal, and in other cases it may mean a problem with the data you are reading; it depends on what you are doing.
Just as VEOFException is, you can derive from VException to define your own specialized exceptions that might contain additional data or simply be separately identifiable in your catch blocks.