When we learn in school user data validation is most often blatantly ignored. I taught myself to validate data with the exception mechanism, but when I try to print useful user messages it feel very clumsy to do that from the exceptions. The more I try the more I feel like exceptions are meant for "inside the code", and they should not "escape" to the end user.
Let's take a simple example. The user needs to enter a command. The format can be: cmd i j or cmd with cmd a predefined set of commands and i and j numbers. We then execute that command.
What I have, from bottom to up is this:
// utility function, converts string to enum
str_to_enum(string str, map<enum, string> s) -> enum
// may throw std::invalid_argument{"cannot convert " + str + " to enum"}
parse_line(string line)
tokens = split(line)
Cmd cmd = tokens[0]; // calls str_to_enum, lets the exception pass by
if (tokens.empty())
throw std::invalid_argument{"empty string as command"s};
if (...)
throw std::invalid_argument{cmd.spelling() + " does not take any argument."};
if (...)
throw std::invalid_argument{cmd.spelling() + " takes exactly 2 arguments."};
str_to_int(tokens[1])
str_to_int(tokens[2]) // throws std::out_of_range
main_loop() {
get_line(line);
try {
Full_cmd full_cmd = line; // calls parse_line, may throw
if (...)
throw std::invalid_argument{"Coordinates out of range"};
try {
execute_cmd(full_cmd); // may throw
}
catch (std::exception& e) {
cerr << "error executing command:" << endl;
cerr << e.what() << endl << endl;
}
}
catch (const std::exception& e) {
cerr << "Invalid command '"s << line << "': " << endl;
cerr << e.what() << endl;
}
}
I think the above logic can be easily followed.
Now, if I want to just display the cryptic "Invalid command" and "Error executing command" then all would be easy. But I want meaningful messages, like the ones I tried above. One problem is that e.what doesn't feel the proper vesel for this. It contains succinct, often technical details. Another problem is that for instance the error "cannot convert <input_string> to enum" reaches the user. While he gets the real string he input, the enum part is implementation detail and criptic for him.
What I see are 2 solutions:
Use std::exception errors.
catch errors at almost any step and rethrow with a reworked message. E.g. from "Cannot convert to enum" to "Command not found".
At the topmost level catch std::exception and basically print e.what()
create exception classes for each type of error (e.g. invalid_command, invalid_no_args etc..
If necessary add more information (other data members) to it in order to have the complete context of the error
once an exception is thrown, it bubbles up to the topmost level
Then at the top-most level, catch each custom exception type and print accordingly.
I obviously went with the first approach. The big downside are the imperfect messages the user gets.
For the second one I feel there is a disproportionate effort vs gain. There would be a lot of boring redundant work just to create the custom exception classes. I tried it once and gave up after the 7'th almost identical class each fully equipped custom data members and constructors and what methods (that set and use those members)
Also, couldn't help but feel I'm reinventing the wheel.
My question is: are exceptions solely a good tool to convey error messages to the end user? If so what is the right way of doing it? If not, how can it be done?
The first approach is not the right approach, for two reasons:
As you have witnessed, it represents a tremendous amount of work.
It presumes that programmers may possibly manage to code into an exception object an error message that could potentially be meaningful to a user. They can't; It wouldn't. If not for any other reason, then at least because statistically speaking, the language in which the programmers will write the message is unlikely to be a language understood by the user. (And I mean this primarily from a linguistic standpoint, though the "level of technicality" standpoint is also worth considering.)
The second approach is in the right direction, but with some modifications:
Drastically reduce the number of exceptions that your system may throw by preemptively checking for mistakes and presenting error messages like "I will not allow you to do this" instead of messages like "what you did was bad, and it failed".
Drastically reduce the number of exception classes that you have to define at each level of your system by making each exception simply stand for "failed to [do whatever this level was trying to do] because such-and-such exception was thrown by a level below". By storing a reference of the "causal" exception into the new exception, you save yourself from having to write lots of new exceptions at each level, with lots of member variables etc.
Realize that human-readable error messages inside exceptions are completely useless: never write such a message, and never show such a message to the user. The message of an exception is the class name of the exception. If you have RTTI, (Run-Time-Type-Information,) use it. Otherwise, just make sure that each exception object knows the name of its own class. This is for your eyes only, and when you see it, you know unambiguously which exception it is.
At the top level of your system, only display error messages to the user about exceptions that you can test. Yes, this means that you have to be able to set up your system so that the exception will actually be thrown, so that your testing code can make sure that the exception was caught and the right error message was issued.
For exceptions that you cannot test, do not even bother showing a message. Just display a general-purpose "something went wrong" error, (along with a nice humorous image perhaps,) and append as much information as you can to your application's log, for your forensic analysis later.
TL;DR
My question is: are exceptions solely a good tool to convey error messages to the end user? If so what is the right way of doing it? If not, how can it be done?
Yes, exceptions are solely meant to convey error/exeptional conditions to the client.
They are not meant to introduce any program control flow in conjunction with catch() or final statements.
The big downside are the imperfect messages the user gets.
You have many options to provide useful messages using the std::runtime_error exception.
Related
I was reading this document Error Handling on the boost website.
in the point five i found this suggestion.
Blockquote
"Don't worry too much about the what() message. It's nice to have a message that a programmer stands a chance of figuring out, but you're very unlikely to be able to compose a relevant and user-comprehensible error message at the point an exception is thrown. Certainly, internationalization is beyond the scope of the exception class author. Peter Dimov makes an excellent argument that the proper use of a what() string is to serve as a key into a table of error message formatters. Now if only we could get standardized what() strings for exceptions thrown by the standard library..."
I'm wondering on how this can be realized( in a language independent way ) but i'm not so experienced.. can you make some examples ?
Thanks!
As it happens so often, "it depends" :-)
I find the what() method extremely useful in command-line applications written for advanced users (I develop scientific software). Here internationalization is not an issue as everyone understands English, and in most cases it is indeed possible to provide error messages that are meaningful to the users.
Another approach I often use is an "error class". An instance of such a class "collects" error messages and warnings while the main application runs and it prints what has been collected only upon exit. It looks like this (only the skeleton is shown to illustrate the principle):
class Errors {
public:
void add_error(const std::string& errmsg);
void add_warning(const std::string& warnmsg);
// print all errors and warnings
void print(std::ostream& out) const;
// no errors, no warnings
bool perfect() const { return (_errs.size() + _warns.size()) == 0; }
// no errors, maybe some warnings
bool ok() const { return _errs.size() == 0; }
// ...
private:
std::vector<std::string> _errs, _warns;
};
The output of what() can be saved directly in an Errors object:
try {
// ...
} catch (const std::exception& ex) {
errors.add_error(ex.what());
// ...
}
or you can generate very nice error messages, possibly internationalized, in the catch block as you see fit by translating the output of what() or by using complex exception objects that encapsulate the necessary information. Then at the end of the program you can give the user a complete list of what went wrong by invoking the print() method.
Finally, if you write software for "non-expert users", then all the caveats noted by others above apply. Basically, internationalized, easy-to-understand error messages should be presented, and only as few as possible. You should "hide" the exceptions, so to speak. No one likes popups saying "Error #x7582764 occurred, exiting" :-)
The issues of error reporting are complex. The comments on the
Boost site are mostly relevant to library code; there is no
really standard way of handling internationalization, for
example, so you cannot generate language dependent messages at
the library level (unless the library assumes one particular way
of handling it, which you generally don't want). The second
point is more general. Even neglecting internationalization, if
the exception is deep in library code, it's highly unlikely that
you could create a message which would be meaningful to a user.
In such cases, the best you can do is pass enough information up
so that the application can catch the error and generate
a meaningful message in the context of what it was doing. Thus,
instead of something like "no entry 'xyz' in table", you might
want to output "Unknown type 'xyz' when deserializing data in
file 'abc'".
Does anyone know a opensource c++ application with a well designed/robust exception mechanism so I can get some inspiration? Most code/examples I see do questionable things like:
Throw objects with a message string as argument. Seems wrong because it marks the exception as fatal, a error message wich can be displayed to the user higher up leaves little room for client code trying to handle the exception. Even if the exception is fatal, things like diffirent locales (languages) makes formatting a message at the point of throw seem like a bad idea to me.
Use tons of different exception classes derived from a base exception class. Just feels wrong introducing a new class/type for every single thing that can go wrong (open file, read file, write file, create thread, etc...). Catching all unhandled exceptions at the highest level using the base type loses type information required to display meaningfull error messages.
Use one exception class derived from a base exception class for every component/library and give it a error code as argument to indicate the exact error. Catching with base type results in ambiguity. (Whose error code "3" did we catch? )...
Some pointers in the right direction would be welcome.
To address all three of these, I found that the best for me is to throw my own custom exception that's derived from std::runtime_error. Like this:
#include <exception>
class ChrisAException : public std::runtime_error
{
/// constructor only which passes message to base class
ChrisAException(std::string msg)
: std::runtime_error(msg)
{
}
}
It allows accepting a string, which I always put in something like the following format (assuming x negative was not a valid input and meant something calling it was in error):
#include "ChrisAException.h"
void myfunction(int x)
{
if(x < 0)
{
throw ChrisAException("myfunction(): input was negative!");
}
// rest of your function
}
For this one, keep in mind that the strings in these exceptions are more for the programmer than the end user. It's the programmer of the interface's job to display something meaningful in the locale when there's a failure. The strings in the exception can either be logged or seen at debug time (preferable!)
This way you can ultimately catch it with:
try
{
// high level code ultimately calling myfunction
}
catch(ChrisAException &cae)
{
// then log cae.what()
}
catch(std::runtime_error &e)
{
// this will also catch ChrisAException's if the above block wasn't there
}
catch(...)
{
// caught something unknown
}
I personally don't like deriving too many types of exceptions, or giving an error code. I let the string message do the reporting.
In general, I use C++ exceptions to mean "something went wrong with the program" and not to handle normal use cases. Thus, for me, a thrown exception during the algorithm execution either means "flag the user that something went wrong" or "don't tell the user" (depending on how critical that code was to what they were doing) but certainly log it and let the programmers know somehow.
I don't use C++ exceptions to handle cases that aren't essentially programming errors, e.g., some kind of incorrect logic or something being called wrong. For example, I wouldn't use C++ exceptions to handle normal program situations like an empty DVD not being in the drive for a DVD writing program. For that, I'd have explicit return code that allows the user to know whether an empty DVD was there (maybe with a dialog etc.)
Keep in mind that part of C++ exception handling is to unwind the stack up to a try-catch block. To me that means, abort what's going on in the program and clean up the stack. In the case of something like my DVD example, you shouldn't really want to unwind much of the stack. It wasn't catastrophic. You should simply let the user know and then let them try again.
But again, this is my preferred way of using C++ exceptions, based on experience and my reading. I'm open to opinions otherwise.
edit: Changed std::exception to std::runtime_error based on commenter advice.
In C++, RAII is often advocated as a superior approach to exception handling: if an exception is thrown, the stack is unwound, all the destructors are called and resources are cleaned up.
However, this presents a problem with error reporting. Say a very generic function fails, the stack is unwound to the top level and all I see in the logs would be:
Couldn't read from socket: connection reset by peer.
...or any equally generic message. This doesn't say much about the context from which the exception is thrown. Especially if I'm running something like an event queue processing loop.
Of course I could wrap every call to socket reads with a try/catch block, catch the exception, construct a new one with more detailed context information and re-throw it, but it defeats the purpose of having RAII, and is slowly but surely becoming worse than handling return error codes.
What's a better way for detailed for error reporting in standard C++? I'm also open to suggestions involving Boost.
As James McNellis suggested here, there is a really neat trick involving a guard object and the std::uncaught_exception facility.
The idea is to write code like this:
void function(int a, int b)
{
STACK_TRACE("function") << "a: " << a << ", b: " << b;
// do anything
}
And have the message logged only in case an exception is actually thrown.
The class is very simple:
class StackTrace: boost::noncopyable // doesn't make sense to copy it
{
public:
StackTrace(): mStream() {}
~StackTrace()
{
if (std::uncaught_exception())
{
std::cout << mStream.str() << '\n';
}
}
std::ostream& set(char const* function, char const* file, unsigned int line)
{
return mStream << file << "#" << line << " - " << function << " - ";
}
private:
std::ostringstream mStream;
};
#define STACK_TRACE(func) \
StackTrace ReallyUnwieldyName; \
ReallyUnwieldyName.set(func, __FILE__, __LINE__)
One can use __PRETTY_FUNC__ or equivalent to avoid naming the function, but I have found in practice that it was too mangled / verbose for my own taste.
Note that you need a named object if you wish it to live till the end of the scope, which is the purpose here. We could think of tricky ways to generate a unique identifier, but I have never needed it, even when protecting narrower scope within a function, the rules of name hiding play in our favor.
If you combine this with an ExceptionManager (something where exceptions thrown register themselves), then you can get a reference to the latest exception and in case of logging you can rather decide to setup your stack within the exception itself. So that it's printed by what and ignored if the exception is discarded.
This is a matter of taste.
Note that in the presence of ExceptionManager you must remain aware that not all exceptions can be retrieved with it --> only the ones you have crafted yourself. As such you still need a measure of protection against std::out_of_range and 3rd party exceptions.
Say a very generic function fails, the stack is unwound to the top level and all I see in the logs would be [...]
What's a better way for detailed for error reporting in standard C++?
Error handling isn't local to a class or library - it is a application level concern.
Best I can answer you question is that the error reporting should be always implemented by looking first and foremost at the error handling. (And the error handling also including the handling of the error by the user.) Error handling is the decision making about what has to be done about the error.
That is one of the reasons why error reporting is an application level concern and strongly depends on the application workflow. In one application the "connection reset by peer" is a fatal error - in another it is a norm of life, error should be silently handled, connection should be reestablished and pending operation retried.
Thus the approach you mention - catch the exception, construct a new one with more detailed context information and re-throw it - is a valid one too: it is up to the top level application logic (or even user configuration) to decide whether the error is really an error or some special (re)action has to taken upon the condition.
What you have encountered is one of the weaknesses of so called out-of-line error handling (aka exceptions). And I'm not aware of any way to do it better. Exceptions create a secondary code path in the application and if error reporting is vital the design of the secondary code path has to treated just like the main code path.
Obvious alternative to the out-of-line error handling is the in-line error handling - good ol' return codes and log messages on the error conditions. That allows for a trick where application saves all low-severity log messages into internal (circular) buffer (of fixed or configurable size) and dumps them into the log only if high-severity error happens. This way more context information is available and different layers of application do not have to be actively aware of each other. That is also standard (and sometimes literally "standard" - mandated by law) way of error reporting in application fields like safety and mission critical software, were one is not allowed to miss errors.
I've never actually done this, but you could roll your own "stacktrace":
struct ErrorMessage {
const char *s;
ErrorMessage(const char *s) : msg(s) {}
~ErrorMessage() { if (s) std::cout << s << "\n"; }
void done() { s = 0; }
};
void someOperation() {
ErrorMessage msg("Doing the first bit");
// do various stuff that could throw
msg = "Doing the second bit";
// do more stuff that could throw
msg.done();
}
You can have several levels of this (although not necessarily use it at every level):
void handleFoo() {
ErrorMessage msg("Handling foo event");
someOperation();
msg.done();
}
And add more constructors and members:
void handleBar(const BarEvent &b) {
ErrorMessage msg(std::stringstream("Handling bar event ") << b.id);
someOperation();
msg.done();
}
And you needn't write the messages to std::cout. It could be to some logging object, and the object could queue them, and not actually output them to the log unless the catch site tells it to. That way, if you catch an exception that doesn't warrant logging, nothing is written.
It's not pretty, but it's prettier than try/catch/throw or checking return values. And if you forget to call done on success (for example if your function has multiple returns and you miss one), then you will at least see your mistake in the logs, unlike a resource leak.
[Edit: oh, and with a suitable macro you can store __FILE__ and __LINE__ in the ErrorMessage.]
You could add a call stack to your exception. I'm not sure how good this works for release builds but works like a charm with debug. You could do this in the constructor of your exception (to encapsulate it). See here for a starting point. This is possible as well on Linux - eventhough I dont remember how exactly.
I use RAII and exceptions and just have various unit-test-like assert statements throughout the code - if they fail, the the stack unwinds to where I can catch and handle them.
#define APP_ASSERT_MSG(Class,Assertion,szDescription) \
if ( !(Assertion) ) \
{ \
throw Class(__LINE__,__FILE__,szDescription); \
}
For most of my particular use case, all I care about is logging debug information, so my exception has the file and line number in it along with an error message (message is optional as I have an assert without it as well). You could easily add FUNCTION or an error code of some type for better handling.
I can then use it like this:
int nRet = download_file(...);
APP_ASSERT_MSG(DownloadException == ERR_OK, "Download failed");
This makes error handling and reporting much easier.
For really nasty debugging, I used GCC's function instrumentation to keep a trace list of what's going on. It works well, but slows down the app quite a bit.
What I do regularly, FWIW, is not use exceptions, but rather explicit error handling in a standard format (ie: using a macro). For example:
result = DoSomething();
CHECK_RESULT_AND_RETURN_ON_ERROR( result );
Now, obviously, this has many limitations design-wise:
Your return codes may need to be somewhat uniform
Code is cluttered with macros
You may need many macros for various check conditions
The upside, though, is as Dummy00001 said: you can effectively generate a stack trace on demand in the event of a serious error, by simply caching the results. I also use this paradigm to log all unexpected error conditions, so I can adjust the code later to handle unexpected conditions which occur "in the wild".
That's my 2c.
Here's how I handle error reporting in my libraries (this may or may not suit your situation).
First, as part of your design you want a "core" or "system" library that all this common logic will sit in. All you other libraries will then link to the core and use its error reporting APIs, so your whole system has a single compact chunk of logic for handling this mess.
Inside the core, provide a set of logging MACROS such as "LogWarning" and "LogFatal" with documented behavior and expected usage- for example, LogFatal should trigger a hard abort of the process but anything lower than "LogError" is simply advisory (does nothing). The macros can provide a "printf" interface that automatically appends the "LINE", "FILE", and "FUNC" macros as arguments to the underlying singleton object that handles your error reporting.
For the object itself I'll defer to you. However, you want public APIs that configure your "drains"- e.g. log to stderr, log to logfile, log to MS Services log, etc. You also want the underlying singleton to be thread safe, re-entrant where possible, and very robust.
With this system, you can make "exception reporting" ONE MORE DRAIN TYPE. Just add an internal API to that error manager object that packages your logged message as an exception, then throws it. Users can then enable AND DISABLE exceptions-on-error behavior in your code with ONE LINE in their apps. You can put try-catches around 3rd party or system code in you libraries that then calls a "Log..." macro in the catch clauses to enable clean re-throw behavior (with certain platforms and compiler options you can even catch things like segfaults using this).
When writing a function, my implementation very frequently looks like this:
Call a subfunction
If this subfunction fails to execute (because of an exceptional situation): log this failure and abort the current function
Otherwise continue calling other subfunctions, which in turn can fail
A crucial part is the logging. Every function that fails should add a short description to the log. This way, at the level where the exception is handled, the user can be shown a detailed error message.
For example, consider an application where a new user account can be created, and there is a problem with the database connection. The following inverse stack trace results:
SQLDriverConnect() -> "SQLDriverConnect error: Data source not found and no default driver specified"
OpenDatabaseConnection() -> "Failed to open database connection"
CreateUser() -> "Failed to create the new user"
ValidateAndSaveNewUserAccount() -> "Failed to save the user profile"
Catch the exception and show the logged messages to the user
Using the exceptions feature, I would implement this 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'd write the following:
bool CreateUser(Log& log)
{
if (!OpenDatabaseConnection(log))
{
log.Add("Failed to create the new user");
return false;
}
//...
return true;
}
I find both implementations equally good. Therefore, I don't see much advantage in using exceptions. I am well aware that exception handling is generally considered a useful feature, but I don't really understand why. A long time ago, I used exception handling extensively, but I didn't see the big advantage, so now I never use them anymore. Hence my questions:
Using exceptions, how can this be implemented in C++ more concisely?
If not, what is then the advantage of throwing exceptions over returning an "is successful" boolean?
Note: I use the term logging as "collecting an explanation of what went wrong, so it can be presented to the user later on". I'd rather not store that explanation in a global collection of log messages (in memory, in a file or in a database), as it directly describes the specific exception.
Update: Thanks for you responses so far. I understand that exceptions are only useful if the user doesn't need detailed feedback on what went wrong. (Please correct me if I misinterpreted this.)
Your strategy seems to avoid the most useful aspect of exceptions, you can throw an exception class which already has the text of the log information in it - that is generate the text for the log at time the exception is thrown not at the time the exception is caught. Then you don't have to catch at every level going up the stack, but only at the top level.
Thus only one try block, and one log.add - much less code in general.
Something like this seems to remove all your replication.
void OpenDatabaseConnection()
{
if (Error) throw MyException("Failed opening database");
}
void CreateUser()
{
try {
OpenDatabaseConnection();
//...... do everything here
}
catch(MyException& E) { //only one copy of this code
E.AddLog(E.getMessage());
throw;
}
}
If you always want to handle your exceptional conditions immediately after the call, then there is no real advantage.
The advantage comes when you want to handle the condition several layers up the call chain. To do that with your success flag, you'd have to bubble the flag up several layers of subroutine calls. Every layer would have to be written with the knowldege that it has to keep track of the special flag from way down in the bowels of the code. This is just a major primo PITA.
For instance, for realtime work we typically build our applications around an iteration loop. Any error during the loop generally just aborts that iteration of the loop (excepting "fatal" errors, which abort the entire app). The easiest way to handle this is to just throw exceptions from wherever they occur, and handle them all in their own catch blocks at the very outermost of the application.
I think a big case for using exceptions here is that you've now made logging part of your method signatures. In general, I don't think that should be the case, because it's a cross-cutting concern. Imagine trying to do an analogous thing with user permissions, for example. Are you going to write this everywhere?
bool CreateUser(Log& log, UserSecurityContext& u) {
if (!HasPermissionsFor(u, SecurityRoles::AddUser)) {
log.Add("Insufficient permissions");
return false;
}
//...
return true;
}
There are other reasons to want to use exceptions (see Elemental's answer), but anytime the non-use of a language feature impacts the design of your software, it's worth thinking about whether that was the right way to do it.
Exception handling removes error handling from the normal control flow. This way, the code structured more clean. Exception handling also unwinds the stack automatically. This way, you need not to include error handling code in each method called on the way to the error. If you need one of those features, go with exceptions. If you don't, use error-codes or any other method because exceptions have costs (computing time) even if they are not thrown.
Additional answers to your comment. Imagine a code, that calls several functions that may fail.
procedure exceptionTest(...)
{
try
{
call1();
call2();
call3();
call4();
}
catch (...)
{
//errorhandling outside the normal control flow
}
}
without exception:
procedure normalTest(...)
{
if (!call1())
{
//errorHandling1
}
else if (!call2())
{
//errorHandling2
}
else if ....
...
}
As you can easily see, the normal control flow is disrupted with error handling. Compared to this code, the code using exceptions is easier to read.
If you need to add error handling in each method you call, exceptions may not provide benefits. But if you have nested calls that each may generate errors, it may be easier to catch the exception at top level. That's what I meant. It is not the case in your example, still it's good to know where to benefit from exceptions.
Exceptions are using in only extreme situations. Execution of exception is too slow. For log not great errors try use return value.
Example:
int someMethod{
if(erorr_file_not_found){
logger.add("File not found");
return 1;
}
if(error_permission){
logger.add("You have not permissons to write this file");
return 2;
}
return 0;
}
In this case you can print error and process this error on higher level.
Or (more complex):
int someMethod{
int retval=0;
if(someshit){
retval=1;
goto _return;
}
//...
_return:
switch(retval){
case 1:logger.add("Situation 1");break;
case 2:logger.add("Situation 2");break;
//...
}
/*
close files, sockets, etc.
*/
return retval;
}
This way is more hard but most fast.
Depending on your circumstances, you may be able to log from a constructor of your exception (maybe asynchronously) That way your code would look like:
void CreateUser()
{
OpenDatabaseConnection();
}
Of course, you would need to throw your custom exception from OpenDatabaseConnection().
I worked on two projects when this strategy was used with success.
I would propose to separate error handling from logging and from the user interaction.
Every method can write to log files for itself. With a small log message framework, methods can output debug, informational and error message. Depending on the context your applications runs in defined by a config file, e.g., only critical error messages are actually written.
Especially in networking applications, connection failures can always occur and are not exceptional. Use exceptions for unexpected errors that should not occur or that occur only rarely. It can also make sense to use exceptions internally if you need e.g. the stack unrolling feature:
void CreateUser() {
try {
CDatabaseConnection db = ConnectToDatabase();
InsertIntoDB(db, "INSERT INTO ... ");
SetPermission(...);
} catch(...) {}
}
If InsertIntoDB throws an exception because the network connection is lost again, object CDatabaseConnection will be destroyed and SetPermission is never run. Using this can lead to better code.
The third thing you want to do is give the user feedback in an interactive application. That's a whole different thing. Let your internal methods return enumerations of possible error codes eerrorCONNECTIONLOST, eerrorUSERNAMEINVALID, etc Don't return the error strings from core methods. The user interface layer should bother which strings to display (possibly internationalizing them). Internally, the error codes will be much more useful. You could e.g. retry five times if your login method returned eerrorCONNECTIONLOST.
I have a c++ dll which I need to debug. Due to the circumstances in which I am using the dll, I am unable to debug it via the calling application.
So, I created a try -catch, where the catch writes the exception to a file.
The line which needs to be debugged involves imported classes from a 3rd party dll, so I have no way of knowing what type of exception it is. When I tried catch(exception e), no message was written to the file. So I tried catch(...), which did trigger something:
using std::exception::what, the only thing that got written to the file was "1".
using std::exception::exception, the file received the following code : "0579EF90".
Is there any way for me to retrieve meaningful info about the exception that was thrown?
TIA
CG
If you don't use catch(KnownExceptionType ex) and use your knwoledge about KnownExceptionType to extract info, no you can't.
When you catch with catch(...) you are pretty much lost, you know that you handled an exception but there is no type information there, there is little you can do.
You are in the worse case, an exception coming out from a library, you have no info on the exception, even if you had headers for the lib, that exception type doesn't need to be defined there.
If I understand you correctly, you've already narrowed down the source of the issue to a specific call to a 3rd party library, but you're not allowed to debug the application live (do I want to ask why?), and your question is "how can I debug the exception without any knowledge of what the exception is"
The answer is, you can't. As you observed, you can blindly guess and hope to catch the right thing. You can also catch(...), but that will tell you exactly nothing. If you could debug live, you could set the debugger to break when the exception is thrown and see what is going on there.
I think the right answer though is to contact the 3rd party library you've narrowed down the source of the issue to and ask them. It is very, very bad form to throw an exception and allow it to propogate across module boundries. It makes me suspect that it's a Windows SEH exception for a null pointer deref or something, and you're compiling in such a way that catch(...) catches those.
maybe try catching std::exception & e
std::cout << e.what() << endl;
see if you can cast it to std::logic_error, and std::runtime_error - that should give you some clue what you're dealing with
Firstly, you should always catch exceptions by const reference, in other words:
catch( const std::exception & ex ) {
...
}
Not doing so means that your exceptions will be of the exact type you catch and this may result in the loss of exception information.
However, it seems that your library is throwing something not derived from std::exception - you need to find out what the type (ideally the base type) is.
I'm a bit confused. On the one hand you write catch(std::exception) didn't work (you should use catch(const std::exception&), BTW), on the other hand you also write you invoked std::exception::what(). How did you do this if you didn't have a std::exception in the first place?
Anyway, once you have caught anything but ..., you could try to log the RTTI info:
#include <typeinfo>
try {
foreign_code(my_data);
} catch(const some_type& x) {
std::cerr << "Yikes! Caught exception of type '"
<< typeid(x).name()
<< "' with its hand in the cookie jar!\n";
std::abort();
}
While the standard doesn't make any assumptions of the result of std::type_info::name(), most (if not all) compilers will generate code that emits something that's at least somewhat useful.
When you're inside the VS debugger, you could also set it up so that it will stop at any exceptions thrown. That gives you a stack trace and thus might give you a clue as to what data passed to the DLL could have cause the problem.