are exceptions expensive on a render engine?

Started by
23 comments, last by SiCrane 11 years, 11 months ago

We're talking past each other here. What I mean by "sound in the abstract" is that assignment is a perfectly reasonable thing to be able to want to do.

Yeah, I don't see how you expected anyone to get that from what you posted when I specifically defined what I was referring to with 'algorithm' - "The problem is the underlying algorithm: memberwise assignment."


I'm saying that I believe it's easier to see that this is the correct way of doing things when you choose or are forced to use error codes over exceptions.

Had you said this originally I probably wouldn't have commented on it. However, it is irrelevant to your original complaint about compiler generated behavior that you don't see the code for. Whether or not code is obviously correct only helps when there is code to actually see.

It's a legitimate complaint to say that the default compiler generated behavior for the assignment operator has issues. However, the default behavior of compiler generated functions not magically doing what you want it to for every situation has only a tenuous connection with exception handling being part of the language or anyone choosing to use exception handling in their own code. Default behavior is exactly that: behavior for the default situation. This being C++, this default behavior emphasizes speed over correctness.

You can't blame exceptions for the fact that C++ has object assignment; it inherited struct assignment from C which doesn't have exceptions. You can't blame exceptions for the fact that C++ has operator= overloads, since that was something developed before the language was even called C++, in C with Classes, which also predated exceptions. If anything, the causal order is reversed, exceptions were added to C++ because things like assignment and constructors had issues with error situations. If you disable exceptions in your compiler you still need to manually implement the assignment operator if you want the strong guarantee. Yes, the default memberwise assignment is a potential problem, but exception handling is not to blame for it.
Advertisement

If you go with exceptions, there's the question of whether you ever catch exceptions in the renderer itself, or whether you always let them propagate to the user code. If you let them propagate, throwing an exception in the middle of the render loop (let's say that object 90 out of 100 threw an exception when rendering, and continues to do so on subsequent frames) may leave out calls to important Direct3D functions, like EndScene() or Present(), which leads to the application appearing frozen even if the user code catches the exception.

The usual response to that is to use RAII objects to make sure functions like EndScene() are called. There's a reason that the compiler goes to so much trouble to make sure the stack is unwound when an exception is thrown.
Yes, the missing EndScene() or Present() is quite an easy thing to safeguard for, but what may be more involved (and which I should have originally mentioned) is ensuring that the renderer's internal state is not messed up in such way that drawing the next frame will also fail, or crash, when interrupted at an arbitrary point. I'm sure it's easier when designed and accounted for up-front.

[quote name='edd²' timestamp='1336691063' post='4939162']
We're talking past each other here. What I mean by "sound in the abstract" is that assignment is a perfectly reasonable thing to be able to want to do.

Yeah, I don't see how you expected anyone to get that from what you posted when I specifically defined what I was referring to with 'algorithm' - "The problem is the underlying algorithm: memberwise assignment."
[/quote]
I explicitly mentioned copy-and-swap as being the best solution, the lack of composition in exception safety, and no one else has had the same complaint about that post, so I don't think the expectation is entirely unreasonable. I certainly could have been clearer so any help with improving my communication is very much appreciated. I can only apologise for my lack of skill here and aim to improve, but I'm not fishing for an argument. I'm merely trying to help the OP decide what to do and present the pros and cons to using exceptions. The best thing you could do, I think, is to help me make my argument/evidence clearer and then tear it down if you still disagree with it.

To be clear: I have nothing against the notion or inclusion of compiler-generated functions/operators.

I was trying to say:

The correct use of exceptions requires an ever-present and deep awareness of the surrounding code and the code it depends on, and the code that code depends on, and so on. It also requires careful analysis of what the calling code might be doing and what it has to know about your code, especially given that the calling code might not be yours.

It seems to me that there's a common perception that exceptions make error handling easier. After a number of years of being aware of these issues, I'm still not convinced of that. In order to use exceptions correctly, one must not only know about

  • the Abrahams guarantees
  • RAII, smart pointers, destruction order, why a 'finally' keyword isn't needed in C++
  • the copy-and-swap idiom
  • how exception safety does not automatically compose
  • the pitfalls of copy-on-write w.r.t exceptions
  • why having a particular base appear twice in the inheritance graph of an exception class can cause problems at catch sites
  • why destructors must not throw
  • why exception class copy constructors and assignment operators must not throw
  • why C++ exception specifications are/were probably a bad idea
  • why you can't (in general) throw from callbacks passed to C code
  • when/if exceptions can be propagated out of dynamic libraries
  • etc

but one must actually cultivate a mindset where all of these things are considered when writing code. I like to think I can do that, but it takes a lot of practice and I honestly still find it quite hard after a number of years. The inadequate compiler-generated assignment operator I mentioned in an earlier post is one example of a situation — and quite a common situation, I suspect — where relatively deep knowledge and a certain mentality is required merely for correctness, despite the code's apparent simplicity.

Some of these considerations disappear when errors codes are used instead, and any considerations that remain are made explicit due manually having to handle/convert/propagate error conditions, which despite the added verbosity, I think is probably a good thing overall. So I'm somewhat on the fence as to whether exceptions are a good idea. It tends to make code shorter, easier to read and often more direct, but I don't think it makes code easier to work with.

So I would say that while the performance impact of using exceptions should be considered as part of any decision, it is secondary to ensuring that you, your team and any in-house clients of your team's code can actually use exceptions properly.

The inadequate compiler-generated assignment operator I mentioned in an earlier post is one example of a situation — and quite a common situation, I suspect — where relatively deep knowledge and a certain mentality is required merely for correctness, despite the code's apparent simplicity.

Which isn't something specific to exceptions. Again, the algorithm chosen predates exceptions in the language. Again, if you disable exceptions in the compiler, you still need to know how the compiler generated behavior works. Most of the rest of your post contains legitimate opinions, but you're backing up your opinions with a faulty argument. You're placing the blame for an issue you need to keep in mind with any error handling strategy on exceptions alone. If anything, the problem here is operator overloading which creates the apparent simplicity that you're complaining about, but again operator overloading predates exceptions as part of the language.

If you want to talk about how useless exception specifications are, I'm with you on that. If you want to talk about why exceptions are a really bad idea on module boundaries, then go to town. Same with the vagaries of various exception implementations or the wacky hi-jinks that arise from C++ allowing the throwing and catching of arbitrary types. There are so many perfectly good complaints about exceptions to choose from that seeing you trying to justify a bad one is rather frustrating. What code a compiler generates for any given expression is something you need to know no matter what error handling strategy you use. This would be a great example for why error handling in general in C++ is hard. I'd say it'd be a fair example to use for avoiding operator overloading. It's just not a good example for avoiding exceptions.

Similarly, some of the things you listed as prerequisites for exception handling are things you should know even if you don't use exception handling. You already demonstrated copy and swap in non-exception code. RAII and smart pointers are also useful tools in non-exception code. Destruction order can still cause headaches in non-exception code. Again, I have no issues with complaining about exception handling, just make sure that the things you're complaining about really are the fault of exception handling.

This topic is closed to new replies.

Advertisement