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!
Posted 10 May 2012 - 11:16 AM
HR = SomeD3DFunction( bla bla bla ); if( FAILED( HR ) ) throw SomeDeviceException();
Posted 10 May 2012 - 11:33 AM
Posted 10 May 2012 - 11:52 AM
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.
Posted 10 May 2012 - 12:26 PM
Posted 10 May 2012 - 12:26 PM
Posted 10 May 2012 - 12:37 PM
Edited by Washu, 10 May 2012 - 12:40 PM.
In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX
Posted 10 May 2012 - 12:48 PM
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).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.
Edited by SiCrane, 10 May 2012 - 01:29 PM.
grammar
Posted 10 May 2012 - 12:57 PM
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.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).
Posted 10 May 2012 - 01:34 PM
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.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.
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).
Edited by Washu, 10 May 2012 - 01:41 PM.
In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
ScapeCode - Blog | SlimDX
Posted 10 May 2012 - 01:47 PM
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;
};
Posted 10 May 2012 - 01:48 PM
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.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.
Posted 10 May 2012 - 04:04 PM
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.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.
Posted 10 May 2012 - 04:39 PM
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.Is this really a problem with exception handling?
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 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?
If the underlying algorithm is bad, whatever error signaling method you use won't help.
Posted 10 May 2012 - 04:51 PM
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.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.
Posted 10 May 2012 - 05:04 PM
No, it's not.
The algorithm is sound in the abstract
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);
Posted 10 May 2012 - 05:10 PM
as if address assignment throws, you'll end up with a corrupted Contact (in the sense of a name/address mismatch).
Contact c(name, address); // I can only get here if no exception was thrown
Posted 10 May 2012 - 05:12 PM
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
Edited by edd², 10 May 2012 - 05:13 PM.
Posted 11 May 2012 - 02:02 AM
There's no such thing as SomeD3DFunction.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!
Posted 11 May 2012 - 07:59 AM
Edited by mdwh, 11 May 2012 - 08:00 AM.
Posted 11 May 2012 - 03:35 PM
"If I die I have to go before him, and he will ask me 'Forward or deferred rendering?' And if I don't know which he will cast me out of Valhalla and laugh at me! That's Crom - strong in his mountain!"