When writing a function, my implementation very often looks like this:
- Subfunction call
- If this sub-function fails (due to an exception): register this failure and interrupt the current function
- Otherwise, continue to call other subfunctions, which, in turn, may fail
The most important part is registration. Each failed function should add a short description to the log. Thus, at the level where the exception is handled, a detailed error message may be displayed to the user.
For example, consider an application in which a new user account can be created and there is a problem connecting to the database. The following reverse stack trace:
- SQLDriverConnect () → "SQLDriverConnect Error: Data Source Not Found and Default Driver Not Specified"
- OpenDatabaseConnection () → "Failed to open database connection"
- CreateUser () → "Failed to create a new user"
- ValidateAndSaveNewUserAccount () → "Failed to save user profile"
- Catch exception and show logged messages to user
Using the exception function, I would do it as follows:
void CreateUser()
{
try {
OpenDatabaseConnection();
}
catch(std::exception& e) {
e.AddLog("Failed to create the new user");
throw;
}
}
Using a simple return value, I would write the following:
bool CreateUser(Log& log)
{
if (!OpenDatabaseConnection(log))
{
log.Add("Failed to create the new user");
return false;
}
return true;
}
. . , , , . - , , . :
: logging " , , ". ( , ), .
: . , , , . (, , .)