The only time I do programming in C++ is to write COM code, and COM and exceptions do not mix. The only way to make COM and C++ exceptions mix is to use smart pointers, and as I’ve already discussed, that only makes the situation worse by introducing subtle, impossible-to-find-and-debug bugs in the error handling.
When I write COM code every function call returns an
HRESULT and I carefully ensure that if there is an error, then everything gets cleaned up properly. COM is fundamentally an environment which is based on error return values for error handling. Any additional error state can be provided by stateful objects.
But the .NET CLR is a completely different environment, one with an exception model built deep into the runtime itself and into the framework. You’d be crazy to not use the exception model in a fully garbage-collected environment like the CLR. I write a lot of C++ and C# code that has to work together via Interop; ALL of my C++ functions returns an error code, and none of my C# functions do. That is not to say that there is no error handling in my C# code — far from it! My code is chock full of try-catch-finally blocks to deal with errors.
Programming languages and object frameworks are tools that afford different styles of programming — attempting to mix the style appropriate to one in another is a recipe for unmaintainable code.
Commentary from 2019:
I always meant to do a post showing my style for writing COM programs in C++ without using smart pointers. It was an extremely clear, rigid style that guaranteed that I would not create resource leaks; basically I was simulating exception handling with macros, with exactly one “catch” per method. I don’t recall if I ever wrote that article; if I did, I guess I’ll find it while I’m porting these posts.
In retrospect I no longer entirely agree with the hot take in the final paragraph. C# and F# are both perfectly usable languages that blend different coding styles. That said, I would not want to do a line-for-line rewrite of a C# program in F#, or vice-versa; that really would be unmaintainable.
There was a good question in the comments about the performance of exception handling. My response was that there are two aspects to exception handling performance:
- What is the additional over-all burden imposed by exceptions? An interesting question, but not actually relevant to making a decision. Why? Because in the .NET framework, there is no way to “turn off” exceptions. You’re stuck with this infrastructure. If you can’t change it, there’s no reason to worry about it. If you cannot turn it off then the question is not “are exceptions fast enough in the CLR?” but rather “is the CLR fast enough?”
- What’s the cost of throwing one exception? This second concern I don’t care about one bit. Exceptions are, by definition, exceptional. When one of my programs gets an exception, almost always it is either doing something incredibly expensive already (in which case the cost of the throw is irrelevant) or we are going to report the exception to the user (in which case the program is going to come to a halt.) Either way, the per-throw cost is unimportant.
However, I missed a trick here. There is an additional cost, which is: what is the cost not of throwing an exception, but catching an exception? The jitter generates more code in a method with a try-catch or try-finally, which means that it has less time available in its budget for optimization. And those optimizations get harder to perform because there is more complex control flow to consider.
Still, I wouldn’t give up exception handling and go back to return codes. There are a number of design changes I would have liked to see in the exception system though. But that is a topic for another day.