On Fri, Feb 12, 2016 at 9:02 PM, Michael Marcin
Sorry I don't follow.
Are you suggesting that the raytracer should be inlined into every call site?
I avoid using inline except if the profiler tells me it's needed. If it is needed, then I inline regardless of whether the function emits exceptions or not.
Let me be more explicit.
You certainly wouldn't inline a raytracer (a heavy operation) at every call site, you would just horribly bloat your executable for no benefit and likely achieve a degradation of performance.
Yes, so don't inline the whole thing, do pay the exception handling overhead at the point when you call this high level function. The overhead at this call point will be negligible, because as you say it's a heavy operation. As you call deeper into the raytracer you will get to levels where the exception handling and function call overhead will be significant, and you'll inline those functions.
However the premise is that the code can have errors in cases which are not unexpected (aka exceptional), which are not the result of programming errors (logic errors), which occur because of limits specifically put in place to constrain time and memory consumption of the operation (performance is important even in the error control flow).
Yes.
What I think you're saying is that where I want to write code that looks
like:
result<int> bar() { return std::make_error_code( std::errc::bad_address ); }
int main() { int foo;
auto _foo = bar(); if ( _foo ) { foo = _foo.get(); } else { foo = 0; }
return foo; }
I should instead write code that looks like:
int bar() { throw std::system_error( std::make_error_code( std::errc::bad_address ) ); }
int main() { int foo;
try { foo = bar(); } catch ( std::system_error& e ) { foo = 0; }
return foo; }
And I should expect equal performance?
Obviously not, because you're always throwing. Throw may incur overhead, certainly does on Windows. What I'm saying is that when you don't actually throw, exception handling overhead occurs exactly where function call overhead occurs, and can be eliminated completely by inlining.
I thought it was obvious that that code is trying to illustrate a difference in interface. Obviously bar() is meant to do work that returns an int but sometimes can't and results in an error.
If you're going to choose exceptions to report your errors you're not going to be able to avoid actually throwing because errors *will* occur (as that is the whole premise of this thread).
Let's say in your example, the function throws 50% of the times you call it. Assuming this isn't an anomaly, it means that you're not really throwing to indicate a failure, but to report a result. Obviously that's not a good design. If your function throws to indicate a failure, then the error path will have some overhead, but the normal execution will have zero overhead, as long as the function is inlined. Emil