On 8 October 2013 02:09, Rob Stewart
On Oct 7, 2013, at 5:39 PM, Daniel James
wrote: On 6 October 2013 12:04, Rob Stewart
wrote: If the exception is triggered by an unknown condition, such as you're advocating, then there can be no handler for it. It must, of necessity, unwind to the top. Code cannot rightly continue as if there had been no exception. In that case, there's little gained over an assertion, save for the possibility that other threads may be able to complete independent work.
later:
The likely outcome of failure in this regard, in a non-debug build, is a null pointer dereference elsewhere. Unchecked, that means a segfault. IOW, the problem will be found.
So you're saying that when it's an exception, it's triggered by an "unknown condition" not by a null, which is surely a known condition.
No
"No, there's an unknown condition", or "no, that's not what I'm saying"?
And you're claiming that after an exception the code will continue as if there was no exception.
No, Pete, I think it was, advocated letting thousands of tasks continue while a few failed.
How is that continuing as if there was no exception? There are strategies for recovering from such exceptions, a simple one is the write the code in question in a pure functional style.
If a null pointer occurs somewhere in your code and this class' ctor throws an exception, the handler has no idea of the source of the null pointer. Thus, the you have an unknown condition as far as the handler is concerned. (I had been discussing a handler in main() or a thread procedure, as opposed to one very near the object mis-construction.)
If you're doing individual tasks you know which one was associated with the throw. For many cases that's all you need to know. This does depend on the program, which is why the decision to catch logic errors should be up to the programmer, who knows it better than we do. You don't have to catch the exceptions if you don't want to.
OTOH, if a null is actual stored in the object, then it will eventually be dereferenced, in the general case anyway, and the segfault will indicate which instance was bad. From that you should be able to discover its genesis, at least if the object's address is consistent or the pointee's type is unique. That makes finding the source of the null pointer somewhat more tractable without a debugger.
You'd get better data if the failure was in the constructor. It's more likely that you could associate it with the source of the pointer, which might have been destructed by the time the pointer is dereferenced. (Remember that my main argument is that there should always be a check). And, of course, you don't always get the segfault data, you sometimes don't even get notified that there is a bug. You're making the assumption that after a bug is discovered, you'll be quickly notified and nothing bad will happen in the meantime. Unfortunately, that isn't true at all.
Consider the case of taking the address of a static object.
I hope you're using a do-nothing custom deleter.
There's no need to check for null, so there's no need to risk pipeline stalling on a failed branch prediction or cache invalidation due to the exception construction and throwing code you'd add to the ctor otherwise.
Well, there's premature optimization for you. This is a class that's concerned with safety, not efficiency. If there's a safe option and an unsafe option, then the safe option should be the default, and the unsafe option should be the verbose one. Considering your concerns, why are repeatedly creating shared pointers from a static object? This would have to be a very tight loop if a null check on a value that you have to access anyway is going to make a difference. In which case you might as well create one non-null shared pointer and reuse that, as it will be faster. But if you can't do that, what will this check really cost? The branch prediction should be for the non-null case, if you're concerned about that you can add a hint in some compilers. I'd actually hope that the compiler would optimise the check away in many cases, especially when initialising from a static object. And the exception creation code should be separate the normal code anyway, so it shouldn't stress the cache too much. Then you've got the cost of reserving memory for that shared pointer's count, that's expensive. You might try to avoid that by using enable_shared_from_this, but then you've got the weak pointer check. You're also no longer thread safe and have to have a shared_ptr somewhere, so there's little argument against using a static non-null shared pointer which will avoid both the weak pointer check and the null check, which is surely preferable since you're so concerned about performance. But whatever you do creating this shared pointer is going to require memory manipulation on the heap - that's not free either. But really, the only way to tell is to try it out in a real program.