I have always been very clear about the attitude of exception. First of all, exception is good, otherwise there will not be most of the language support him. Second, the error code is no problem, just need a prerequisite-your language as Haskell have Monad and Comonad. You see Haskell there is no exception, we also write very happy. Why, then? Because as long as the return with the error code results of a function to make a monad/comonad, then you can use CPS transform to turn it into a exception. So the CPS as the same as the same basic control flow statement is really well-deserved, but the CPS is type rich, goto is type poor.
In fact, many people's fear of exception is that you do not know what a function will throw exception out, and then the program a crash you are stupid force. As for the server, the situation is fine, if there is a problem, just kill a quick reboot, and now no replication and fault tolerance have the cheek to say you're writing back-end (so don't know what the Web people are against)? The main problem still lies with the client. As long as the things on the client are not saved, then you crash the data is not--of course it's just your imagination, in fact, it is not like this.
Our program throws an access violation out, and throws out the other exception, what difference does it have? Access violation is a wonderful thing, once thrown out to tell you that your program is hopeless, continue to carry on may also have the destructive effect. Especially for a language like C/c++/delphi, you accidentally write the wrong thing into a messy pointer, and nothing happens, and the program runs the wrong way. Because of your mistake to get the wild pointer, maybe the next door does not know what object member variables, perhaps the heap inside the data structure, or say something else, so write to you. If you write a member variable of another object, the package will not work, and the invariant of this class will destroy you. Since your member functions are written based on invariants, then it is necessary to make an error at this time. If you write the data structure of the heap, it's even more aha, maybe next time a new one will collapse, and you still don't know why.
Out of access violation outside the exception basically is no harm, the most serious probably is the network cable was unplugged, another piece is not installed OS hard disk suddenly bad what this kind of anyway you can not but at least at any possible to deal with things. If these exception are out of your own, that's more reliable--it's all planned. As long as the program does not enter access violation in the future, that proves that all the variables you can get now, and the memory that the pointer points to, are basically reliable. There's a mistake you can't save, at least you can keep the data safe and restart yourself-just like word. But you might say, with access violation, why can't you save the data? Because the memory is destroyed at this time, it is not possible for you to save the data of the code new point and then hang up, which is basically not accurate.
So whether you like exception or the error code, the effect you want to achieve is essentially to avoid the fact that the program will enter the violation state of access in the future. To do this, the method is also very simple and brutal-as long as you check the function before you run it in the function. Whether you use the exception or the error code, you write it all the same. The difference is what happens to the person who calls your function. So let me give you an example where you think the STL map is so stupid that you write one yourself and then have a function like this:
Exception version
symbol* symbolmap::lookup (const wstring& name);
Error code version
int symbolmap::lookup (const wstring& name, symbol*& result);
In fact, COM is your favorite error code style, write should be very happy to ah, your double standard really serious
HRESULT isymbolmap::lookup (BSTR name, isymbol** result);
So after we get the lookup function, we're going to start to do a task, say, take two keys and get two symbol and then assemble a new symbol. The error handling logic of the function is this, if the key fails, because of the business reason, we have to tell the function outside that the key does not exist. It is obviously unreasonable to indexoutofrangeexception what is thrown out of a function that calls a composesymbol. But the combination of that step, because the business is in the same domain, so suppose inside the exception is acceptable. If there is a unplanned exception, then we can not handle, only to be thrown to the above, the outside of the code for the exception only need to report the task failed on it. So that's what our function would say:
symbol* Composesymbol (const wstring& A, const wstring& B, symbolmap* map)
{symbol* sa=0
;
symbol* sb=0;
Try
{
sa=map->lookup (a);
Sa=map->lookup (b);
}
catch (const indexoutofrangeexception& ex)
{
throw symbolkeyexception (ex. GetIndex ());
}
Return Createpairsymbol (SA, SB);
}
It looks pretty good. Now we can start thinking about the version of error code. So we need to think about a few questions. First of all, how do you report when lookup fails? It is not possible to report the contents of a key directly, because the error code is an int.
On the other hand, the error code of course can be something else, if you need to return the rich content of the error, then how all must be a pointer, this time you will face the following problems-this has been his mother who constructs who released the principle of Ah, And I this pointer directly back out of the outside to ignore, if as long as there is a link to ignore, that memory is not leaked? If I asked to return the error to the parameters, I would create a structure to save the exception every time I called the function, not only the complexity of the IF, but also the complexity of creating the space, and the whole code became excrement. So be honest with int bar ...