Sign in to follow this  

are exceptions expensive on a render engine?

This topic is 2044 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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:

[CODE]
HR = SomeD3DFunction( bla bla bla );

if( FAILED( HR ) )
throw SomeDeviceException();
[/CODE]


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

thanks!

Share this post


Link to post
Share on other sites
From a performance perspective, you'd only want to throw an exception on error either if the chances of the error occurring are very low or if program execution is so hosed that performance doesn't matter since you're about to bail (ex: to desktop or the main menu). For MSVC I generally use the estimate of one in ten thousand as the cut off. If the call is more likely to fail than one in ten thousand calls, then don't use an exception. If less, then an exception is fine. So a function like IDirect3DDevice9::TestCooperativeLevel() would be a bad candidate for throwing an exception since a lost device is something that can easily happen and also can be recovered from so you aren't about to bail.

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1336671226' post='4939057']
From a performance perspective, you'd only want to throw an exception on error either if the chances of the error occurring are very low or if program execution is so hosed that performance doesn't matter since you're about to bail (ex: to desktop or the main menu). For MSVC I generally use the estimate of one in ten thousand as the cut off. If the call is more likely to fail than one in ten thousand calls, then don't use an exception. If less, then an exception is fine. So a function like IDirect3DDevice9::TestCooperativeLevel() would be a bad candidate for throwing an exception since a lost device is something that can easily happen and also can be recovered from so you aren't about to bail.
[/quote]

I'm not sure if I entirely agree with that. Exceptions are used in situations where behavior is, well, exceptional. You use exceptions when you _want_ to be able to recover from an error. You use assertions in situations where you don't.

Basically, assertions verify that the contracts between functions are being honored; if a function specifies that it cannot take a NULL parameter, yet a NULL parameter is passed to it, you should use an assertion; that is a logic error. If it was data passing the NULL parameter, the caller should have been aware of the contract and verified it beforehand, possibly using a thrown exception to early-out.

If he's working with code where he must roll-back logic due to a manageable error, then an exception is correct. If it's an unrecoverable error, one should use an assertion.

Ideally, with a renderer, you'd rarely if ever use assertions (only use them to validate function contracts); you want your renderer to be able to recover from errors and at least restart itself.

The alternative to using an exception is to check the return value and do a series of returns, which is no more efficient, and is far harder to read/understand.

Share this post


Link to post
Share on other sites
Assertions are used to flag situations that should [i]never[/i] happen, and only arise from the fundamental assumptions of the programmer being violated. This does not mean just any situation that you know can happen but you can't or just don't want to recover from. For example, being unable to open a script file from disk that contains the core logic of your program is not recoverable, but does not warrant an assertion because file system errors, running the program from a network or external drive or plain bad installs are situations that can actually happen. Every assertion that gets tripped should represent a programmer error, and should not get used for any other situation. In other words, if the end user ever sees an assertion get tripped, then a programmer somewhere has screwed up.

The efficiency of using return values compared to exceptions depends on the relative frequency of the failure situation. Throwing and catching an exception is an extremely costly operation, so if an error occurs frequently then, from a performance perspective, exceptions become more costly than using return values. On the other hand, if an error almost never occurs, then it's more efficient to not have to check a return value. The break even point depends on multiple factors including compiler, but on MSVC it usually turns out to be the roughly one in ten thousand value I mentioned.

Share this post


Link to post
Share on other sites
Be aware that exceptions aren't just something you can add in willy-nilly. Firstly, there's overhead for simply *having* exceptions at all, you don't have to throw an exception to get a performance hit, its there all the time. The overhead is probably negligible in many functions, but for functions which might be called in a tight loop it can be significant.

Another concern is that there's still more overhead, either in implementation, at runtime, or both, to make sure your functions are exception-safe. It's also something that can be difficult to get right. An example is that if you allocate memory inside of a function, and then later the stack is unwound due to an exception, you might not execute the code that frees the memory. If your program is going to bail anyhow, its not big deal, but if you're able to recover from the exception higher up the chain, you've got a source of memory leaks. Proper use of smart pointers can go a long way to solving that particular problem, but its a good example of how using exceptions radically changes the way you have to think about your program's correctness.

On some development platforms portability can also be a concern as well, because exceptions might not be supported. Sticking to PC and (probably) modern consoles it will be well-supported, but you might be out of luck if your code will ever run on an embedded platform or portable consoles. I'm not privy to specifically which development systems might or might not support them, but historically speaking, RTTI and exception handling are usually the first things thrown out the window on less-capable platforms, so its something to keep in mind.

Share this post


Link to post
Share on other sites
I tend to be in the group that suggests against using exceptions unless you actually know what you're doing.

Exceptions introduce a lot of extra work YOU have to manage (smart pointers being one simple example). They also tend to add a certain amount of performance overhead (in C++, this is not completely true in managed languages). Why? Well, there's a couple of things to realize: When an exception is thrown the stack has to be unrolled. In C++ this means fully constructed objects whose scope ends during the stack walk up to the first exception handler that matches the thrown exception has to be destructed. For things like smart pointers, containers, etc. this can be quite expensive (when a vector goes out of scope, it has to first walk all the existing items in it and call their destructors, then release the memory it had allocated).

In addition, there aren't a whole lot of areas in a RENDERER where you actually NEED exceptions. There are a few things that MIGHT call for them, such as errors like "Device was removed." (I've gotten that one before :P). However, in general most errors are quite recoverable, such as the device being lost. In C++ the general rule is that "exceptions are for exceptional events," and a device being lost is a very common occurrence (in D3D9). Other similar issues, such as running out of GPU memory when trying to allocate a texture or vertex buffer are similarly not that uncommon and should be dealt with in a fairly clean and failproof mechanism. All of this generally suggests that you should either provide error code returns (instead of exceptions) or some other form of error notification.

As a last note: Never, and I do mean it, mix exceptions with return codes. There is no interface more confusing than one that attempts to report errors in more than a single way.

As an additional note on the managed side of things: The reason exceptions are more prevalent, other than just a language design decision is that it is quite a bit cheaper for exceptions to propagate than it is in a language like C++. This is because, in most managed languages (like C#, Java, Python), there is no need to walk up the stack destroying objects whose lifetime has ended. These will be automatically collected by the GC. This simplifies the stack walk and reduces the amount of additional information the compiler has to track to figure out what needs to be cleaned up. Edited by Washu

Share this post


Link to post
Share on other sites
[quote name='Ravyne' timestamp='1336674399' post='4939073']
Be aware that exceptions aren't just something you can add in willy-nilly. Firstly, there's overhead for simply *having* exceptions at all, you don't have to throw an exception to get a performance hit, its there all the time. The overhead is probably negligible in many functions, but for functions which might be called in a tight loop it can be significant.
[/quote]
To be fair, checking the return value for functions called in a tight loop can have significant overhead too. In any case, degree and kind for exception overhead is an implementation specific deal. Some compilers add prologue and epilogue code to every function, which obviously causes overhead for every function. On the other hand, some other compilers have what are called "zero overhead exceptions", which is a marketing claim rather than an accurate claim, but the cost takes the form of additional data tables added to the executable rather than specific runtime costs like the prologue/epilogue code. It slows down load time due to increased size, but doesn't actually slow down code execution until an exception is actually thrown. Additionally, compilers frequently give mechanisms to help manage exception handling overhead, such as MSVC's __declspec(nothrow). Edited by SiCrane
grammar

Share this post


Link to post
Share on other sites
[quote name='Washu' timestamp='1336675070' post='4939079']
They also tend to add a certain amount of performance overhead (in C++, this is not completely true in managed languages). Why? Well, there's a couple of things to realize: When an exception is thrown the stack has to be unrolled. In C++ this means fully constructed objects whose scope ends during the stack walk up to the first exception handler that matches the thrown exception has to be destructed. For things like smart pointers, containers, etc. this can be quite expensive (when a vector goes out of scope, it has to first walk all the existing items in it and call their destructors, then release the memory it had allocated).
[/quote]
That's not really an overhead of exception handling. The compiler still needs to unwind the stack and destroy the same objects no matter what language constructs you use to handle program flow. Use a return to leave a function or use an exception to leave a function, the stack gets unwound either way.

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1336676272' post='4939089']
[quote name='Washu' timestamp='1336675070' post='4939079']
They also tend to add a certain amount of performance overhead (in C++, this is not completely true in managed languages). Why? Well, there's a couple of things to realize: When an exception is thrown the stack has to be unrolled. In C++ this means fully constructed objects whose scope ends during the stack walk up to the first exception handler that matches the thrown exception has to be destructed. For things like smart pointers, containers, etc. this can be quite expensive (when a vector goes out of scope, it has to first walk all the existing items in it and call their destructors, then release the memory it had allocated).
[/quote]
That's not really an overhead of exception handling. The compiler still needs to unwind the stack and destroy the same objects no matter what language constructs you use to handle program flow. Use a return to leave a function or use an exception to leave a function, the stack gets unwound either way.
[/quote]
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. All of which is generated by the compiler and thus invisible to the programmer. Although the table based approach (which uses the current call stack to find which destructors to call, I believe) is supposed to be "cost-free" until an exception is thrown.

My only other thing is that I do tend to prefer exceptions over error codes, mainly due to the reduction in spaghetti code that most return based error handling introduces (which it doesn't have to, but it tends to). But that only really works if you've designed your software solution with exceptions in mind. Edited by Washu

Share this post


Link to post
Share on other sites
Depends on the exception handling mechanism. The old SJLJ "personality" that GCC used to use by default was horribly slow. The newer DWARF "personality" will often be cheaper than checking error codes, as the cost is paid only when exceptions are thrown (which should be rare -- you certainly don't want to replace error codes with exceptions entirely). The Visual C++ exception handling mechanism is somewhere in the middle, as far as I understand it; quite fast but not free.

But I'd say that any such decision should hang far more on the skill and experience of the people writing and maintaining the code than on any concerns about efficiency. Writing exception-safe code requires a meticulous attention to detail and an awareness of which code can/may throw. Example:

[code]
struct Contact // for an address book app, or something.
{
Contact(const std::string &name, const std::string &address) :
name(name),
address(address)
{ }

std::string name;
std::string address;
};
[/code]

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.

The burden is probably greater than checking the return code of every function. But with that said, C++'s built-in handling of stack-unwinding and deterministic destruction arguably provides a better baseline than most any other mainstream languages for handling exceptions (when treated as non-fatal conditions).

Share this post


Link to post
Share on other sites
[quote name='Washu' timestamp='1336678490' post='4939102']
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.
[/quote]
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.

Share this post


Link to post
Share on other sites
[quote name='edd²' timestamp='1336679267' post='4939105']
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.
[/quote]
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.

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1336687464' post='4939148']
Is this really a problem with exception handling?
[/quote]
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.

[quote]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.

[quote]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.

Share this post


Link to post
Share on other sites
[quote name='edd²' timestamp='1336689561' post='4939154']
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.[/quote]
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.

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1336690279' post='4939155']
[quote name='edd²' timestamp='1336689561' post='4939154']
The algorithm is sound in the abstract[/quote]
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:

[code]
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);
[/code]

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.

Share this post


Link to post
Share on other sites
[quote]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, [code]Contact c(name, address);
// I can only get here if no exception was thrown[/code]

Share this post


Link to post
Share on other sites
[quote name='Antheus' timestamp='1336691451' post='4939163']
[quote]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, [code]Contact c(name, address);
// I can only get here if no exception was thrown[/code]
[/quote]

I agree with everything you've said [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]

I'm not sure what you're contesting? Note I'm talking about copy [i]assignment[/i], not copy [i]construction.[/i] Edited by edd²

Share this post


Link to post
Share on other sites
[quote name='???' timestamp='1336670207' post='4939050']
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:

[CODE]
HR = SomeD3DFunction( bla bla bla );

if( FAILED( HR ) )
throw SomeDeviceException();
[/CODE]


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

thanks!
[/quote]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.

Share this post


Link to post
Share on other sites
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. Edited by mdwh

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
[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.[/quote]
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 name='edd²' timestamp='1336691063' post='4939162']
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.[/quote]
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.

Share this post


Link to post
Share on other sites
[quote name='AgentC' timestamp='1336772132' post='4939423']
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.
[/quote]
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.

Share this post


Link to post
Share on other sites
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. Edited by AgentC

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1336776017' post='4939442']
[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.[/quote]
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 [i]entirely[/i] 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[list]
[*]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
[/list]
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 [i]apparent[/i] 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. Edited by edd²

Share this post


Link to post
Share on other sites
[quote name='edd²' timestamp='1336821523' post='4939540']
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 [i]apparent[/i] simplicity.
[/quote]
Which isn't something specific to [b]exceptions[/b]. 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.

Share this post


Link to post
Share on other sites

This topic is 2044 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this