Re: Exceptions, Go to Hell!
On 8=E6=9C=8830=E6=97=A5, =E4=B8=8B=E5=8D=883=E6=99=8201=E5=88=86, Goran Pu=
sic <gor...@cse-semaphore.com> wrote:
Really really apologize, the above is not correct.
It should be:
std::vector<T> arr=initialize();
size_t i;
try {
for(i=0; i<arr.size(); ++i) {
if(arr.at(i)==T()) break;
}}
catch(const std::out_of_range& e) {
assert(i>=arr.size()); // Time bomb! Can I really assure=
this
// assertion?
}
I have no idea what your meaning is now. In this code snippet, if
I am very sorry for making replies too randomly. This example is
worse than the original one.
T::operator== does not have some horrible bug^^^, that is completely
outside of the scope of exceptions, assert can never, ever fail.
^^^E.g. buffer overrun that often causes stack corruption in common
implementations). But if you're reading this newsgroup, you know by
now, that corrupting the stack is undefined behavior (UB). If you
invoke UB, you're lucky your hard drive isn't re-formatted :-).
Somehow I don't think we're discussing UB.
No
So yes, if code is bug-free, you can easily assure this assertion.
No, context is lost.
Let's say T is from a commercial company (user's code is clean).
If the company allow you to view their source, you could find there
even no 'throw' is in their codes. The company's codes are also
clean, because the responsible parts relies on other companies' codes.
At least for now to note is that the boundary between interface and
implement is weaker, since there are already many public throw types
exposed, and allowed to change silently. Finally, if the source is
found, they may consist of several instances of std::vector,... all
kind of types can be thrown without violating their specifications.
In general, no way you catch an object you know how to handle it,
even the original programmer won't know how not to rethrow in the
user's code. A function can say in what condition it may throw what
object, but the catch handler can't assert contextual condition.
Consider another similar example:
std::vector<T> v;
const size_t cap=get_needed_cap();
try {
v.reserve(cap);
}
catch(std::length_error&) {
assert(cap>v.max_size()); // Time bomb!
// T(T) may throw std::length_error. program can't have such
// assert, because context is lost.
throw;
}
You can enter the catch if e.g. T::operator== throws
out_of_range^^^^^^, but "i" cannot possibly reach arr.size(), not
unless there's an even worse bug in T::operator==. I am mentioning
T::operator== because that's the only code we can't see. Anything els=
e
is correct (albeit silly) code.
And code is silly because it tries to do is to find T() in arr. To do
this, you do:
std::vector<T>::const_iterator elem std::find(arr.begin(), arr.end(),
T());
if (arr.end() != elem)
// elem found
^^^^^^ if that happens, you still have a bug, because, remember,
anytime any logic_error is thrown, there is a bug. If you catch, and
not re-throw a bug, you just made another bug, because to me, hiding
bugs is a bug in itself.
Roughly agree. I am not thinking the definition of a 'bug' yet,
instead, I am afraid of the same rethrow strategy should
also apply to others because the context is lost, catch handler
can't be sure of the program state in general in the catch handler.
Even user's private dedicated throw type is very restricted in use
to avoid being caught in or with different context.
I remember I read from a book that C++ does not guarantee the proper
handling if the size of thrown object is larger than the standard
exception type.
You remember wrong. In fact, this sentence is nonsense. Particularly,
mixing "size of thrown object" and size of "standard exception type"
is nonsense.
Goran.
I mean sizeof(T), T being any of the standard exception types.
In another word, adding extra data members to std::logic_error or
std::runtime_error might not be handled properly in the stack
unwinding.
IIRC, the memory came from the book "The C++ Programming Language,
by Bjarne Stroustrup", but couldn't find it again.
It would be appropriated if anyone would verify this restriction.