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; } }.
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; } }.
The problem is that this way, the user looses essential information. The log at the level where the problem is detected is too specific for the user, whereas the log at the level where the exception is eventually caught is to general. – Dimitri C.
Nov 25 '09 at 15:18 You CAN still trap exceptions lower in the stack if it is useful to do so - in other words you only need the catch block where you have a good reason for them. You can also throw a new exception from inside the catch block summarising detail that you don't want to pass up the stack. – Elemental Nov 25 '09 at 15:26 You are right: in cases where you don't need to add detailed logging, exceptions are somewhat more concise.
– Dimitri C. Nov 25 '09 at 15:51 Instead of MyException::getMessage I prefer to use a method named what which is compatible with std::exception public interface, virtual const char* what() const throw(); See for instance: www2.roguewave. Com/support/docs/leif/sourcepro/html/stdlibref/… – Francesco Nov 25 '09 at 9:48 Yeah, I think deriving your own exception type from std::exception is a good idea - just didn't want to confuse the issue here.
– Elemental Nov 25 '09 at 20:53.
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.
– Dimitri C. Nov 25 '09 at 15:22 No, I'm saying nothing of the sort. For example, our standard exception class has a log message as a member.
That can get thrown with the exception. The the catch handler has the choice of logging the exception with either its own message, the thrown message, or both. – T.E.D. Nov 25 '09 at 15:47.
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.
Thanks for the reply. Only: are you suggesting that you could eliminate the UserSecurityContext parameter by using exceptions? – Dimitri C.
Nov 25 '09 at 14:53 @Dimitri C. » Right; it shouldn't be part of the method signature (imo). – John Feminella Nov 25 '09 at 14:58 But how would you do it?
How can exceptions eliminate the need for the UserSecurityContext parameter? – Dimitri C. Nov 25 '09 at 15:10.
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.
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.
Removes error handling from the normal control flow": With the example I give, I try to demonstrate that this doesn't work. – Dimitri C. Nov 25 '09 at 14:58 "you need not to include error handling code in each method": yes you do: to add user-readable logging.
– Dimitri C. Nov 25 '09 at 15:00.
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 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. Instead, I want to keep it close to the exception.
– Dimitri C. Nov 27 '09 at 9:34 "Don't return the error strings from core methods": Hm; this seems like an awful lot of work to me. – Dimitri C.
Nov 27 '09 at 9:36.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.