are exceptions expensive on a render engine?

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

Yes and no. If the performance were the same then there would be no reason to use error codes over exceptions. There is a performance difference though, and it does directly relate to the tracking of what needs to be destroyed when an exception is thrown, either through additional tracking information on the stack or in static tables.

I'm not saying that there's no performance difference, I'm saying that objects need to be destroyed either way, so the reason you gave isn't one of the causes of performance difference. A vector on the stack gets destroyed whether you leave the function through a return or through an exception, so talking about how expensive it is to destroy a vector and destroy each of its elements is extremely misleading.
Advertisement

The compiler-generated copy-assignment operator isn't strongly exception safe, as if address assignment throws, you'll end up with a corrupted Contact (in the sense of a name/address mismatch). A contrived example, but it shows that even if RAII is applied ruthlessly, you aren't out the woods; you have to be ever vigilant.

Is this really a problem with exception handling? If you disable exception handling will that prevent a corrupt object? If instead of an assignment operator that uses exceptions to signal errors, the compiler created and used functions that returned error/success would that prevent corruption? The problem is the underlying algorithm: memberwise assignment. This is completely orthogonal to what mechanism is used to signal errors. If the underlying algorithm is bad, whatever error signaling method you use won't help.

Is this really a problem with exception handling?

If your string copying functions return error codes, you'll be more aware of the problem. Of course, the problem exists either way (and arguably copy-and-swap is a nicer solution than error codes) but it's easy to assume (I feel) that exception safety 'composes' in this way, when in fact it does not.

If instead of an assignment operator that uses exceptions to signal errors, the compiler created and used functions that returned error/success would that prevent corruption?
[/quote]
No, but I very much doubt that would have been standardised if exceptions didn't exist, because a compiler can't deduce whether a particular return type/code indicates an error or a 'proper' result. So without exceptions, the programmer would be forced to write the assignment code, providing the opportunity to spot the problem. Of course, without exceptions you would have a hard time implementing "Contact &operator= (const Contact &rhs)" with that signature in the first place, as there's no place to return an error.

If the underlying algorithm is bad, whatever error signaling method you use won't help.
[/quote]

The algorithm is sound in the abstract, but it's easier to implement a concrete version of it correctly when exceptions aren't involved, as you're forced to confront the error conditions.

Of course, it takes discipline to make sure such error codes are checked everywhere, but I often wonder whether it requires more or less discipline to use exceptions correctly. It's easy for the novice to be lulled in to thinking things are easier because they don't have to check error codes everywhere. They'd be right, but other adjustments must be made which arguably require a deeper understanding of the surrounding code an context.

FWIW, I'll likely continue to use exceptions in my personal projects, but I have to take care when collaborating (e.g. at work) because of the different mindset required.

The algorithm is sound in the abstract, but it's easier to implement a concrete version of it correctly when exceptions aren't involved, as you're forced to confront the error conditions.

No, it's not. If you copy the first member and then the copy for the second member fails, you're left with a corrupt object. It doesn't matter how the error is signaled, you've changed the state for the first member already. Implementing a correct version requires a change in algorithm.

[quote name='edd²' timestamp='1336689561' post='4939154']
The algorithm is sound in the abstract

No, it's not.
[/quote]

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.

In either case, the pseudocode must be:


string newname;
string newaddress;

if (newname = rhs.name fails)
return_with_failure_indication();

if (newaddress = rhs.address fails)
return_with_failure_indication();

// Can't fail now, just exchanging a few pointers etc
swap_internals(newname, this->name);
swap_internals(newaddress, this->address);


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.
as if address assignment throws, you'll end up with a corrupted Contact (in the sense of a name/address mismatch).[/quote]

I'm probably missing something, but if constructor throws, you don't have an object.

Or, Contact c(name, address);
// I can only get here if no exception was thrown

as if address assignment throws, you'll end up with a corrupted Contact (in the sense of a name/address mismatch).


I'm probably missing something, but if constructor throws, you don't have an object.

Or, Contact c(name, address);
// I can only get here if no exception was thrown

[/quote]

I agree with everything you've said smile.png

I'm not sure what you're contesting? Note I'm talking about copy assignment, not copy construction.

ok, basically that... I'm starting to build a render engine in DirectX, but I'm not sure how expensive could be to use exceptions to handle some errors.

I'm thinking on doing something like:


HR = SomeD3DFunction( bla bla bla );

if( FAILED( HR ) )
throw SomeDeviceException();



is it safe?.. or would it be too expensive to use?

thanks!
There's no such thing as [font=courier new,courier,monospace]SomeD3DFunction[/font].
Places where I use exceptions:
- Compiling shaders
- Loading/creating graphics resources

Those paths are still exception free, and will probably be for a long time
- Buffer map
- DrawCalls

It's worth noticing most D3D calls don't fail because of "some reason". Most fail because of static reasons such as incorrect parameters or wrong internal state.

Previously "Krohm"

Just a few thoughts:

* One of the advantages of exceptions is you can report a failure in a constructor, which can't be done with return codes. You can get round it by setting a "success" flag which is checked, or having a light constructor and doing everything in an init() function, but both seem less desirable to me.

* The STL works with exceptions anyway, so surely anyone using it with C++ ought to be aware of how exceptions work anyway?

* It's true that exceptions create complications with freeing memory, as the only thing guaranteed to be called is the destructors of objects on the stack, so you end up needing smart pointers and so on. The flip side is that, whilst doing things the C-style way with return codes and manually deleting memory is easier (at least for me) to get your head round, it is also easy to lead to its own problems of memory leaks and missed error returns. So I'd argue using smart pointers is a good thing anyway, and shouldn't be a reason against exceptions.

* I wonder if part of the problem is that DirectX just returns everything as a "failure", even for things like losing the device which are perfectly normally? I mean, if MS had sorted things so that "failure" was only for the exception cases, then using exceptions always would make more sense. But instead, it's left to the caller to try to decide which category each "failure" falls into.

http://erebusrpg.sourceforge.net/ - Erebus, Open Source RPG for Windows/Linux/Android
http://conquests.sourceforge.net/ - Conquests, Open Source Civ-like Game for Windows/Linux

I would second the idea to be wary of exceptions in a rendering engine, though not so much because of performance, but because of usability and robustness. While rendering may require complex dependencies between objects (for example a material referring to textures, shaders and constant buffers) the easy way to bail out of most error situations, such as a missing/failed texture, is simply to not render, or to replace the missing object with an "error asset" to indicate the error visually, while also logging an error and returning an error code.

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.

This topic is closed to new replies.

Advertisement