Re: Questions about "mismatch"
Le 21/12/10 13:30, Leigh Johnston a ?crit :
On 21/12/2010 09:03, jacob navia wrote:
Le 21/12/10 01:17, Leigh Johnston a ?crit :
The fact that iterators are not invalidated for certain operations on
certain containers in the C++ standard library is an important and
useful property; I have code which relies on this and would feel very
uncomfortable trying to use a library which didn't support this.
There are too many rules to learn in the C++ model. Some containers
invalidate everything, others not, others in some operations, etc.
This promotes bugs, it is all too easy to forget some rule. Besides,
if you change the type of the container, the rules change and
previous code that worked stops working.
All this is just a too complex interface. So, I decided to make
a fresh start and a simple rule: do not modify the container
when you are iterating over it except by using the iterator
to delete the current item.
That is a simple interface. No exceptions, easy to learn and
use.
But that is also a design decision. I prefer simple interfaces
that are easy to use rather than complex interfaces that are error
prone. (In my opinion of course).
It is your opinion yes; in my opinion the C++ standard library is fine;
one can create bugs using any language feature.
How would you do the following using your iterator invalidating library?
for (std::set<foo>::iterator i = c.begin(); i != c.end();)
{
if (i->done())
c.erase(i++);
else
++i;
}
/Leigh
Like this:
// "c" is some container: list, vector whatever
void *obj;
Ierator *it = newIterator(c);
for (obj = it->GetFirst(it);
obj != NULL;
obj = it->GetNext(it)) {
if (done(obj)) {
it->EraseCurrent(it);
}
}
deleteIterator(it);
The only change allowed is erasing the current item
pointed by an iterator. This invalidates all OTHER
iterators (if you happen to have more than one) that
use this container but doesn't invalidate the one you are
using. I specified that in another subthread but I do not
remember if I told you this.
The iterators of my library are bidirectional, and they
remember if you last called GetNext or GetPrevious. If
you are iterating forward (with GetNext()) you get positioned
at the previous one than the one erased. If you last
called GetPrevious() you get positioned at the next one after
the one you erase it. If you erase the first one and you were
forward iterating (i.e. you did GetFirst() and then EraseCurrent())
You still get positioned at the first one, since there is
no previous. If the container contained just one element
the iterator is invalidated since there are no elements.
Note that my iterators return NULL when invalid, they will NEVER
go beyond the limits of the underlying container, and they will
never return a bad pointer. When they are invalidated, they
just return NULL.
This are roughly the specs but they are not fully implemented yet.
This is a work in progress.
It is true that you can write buggy software in ANY language,
but that should not hinder us to try to specify the BEST interfaces
and avoid error prone constructs.
Error-prone means in this context that
(1) There are many rules to remember without underlying principles.
In C++ you have to know the specifics of each container to know
if the iterators are invalidated or not.
(2) Any error leads directly to catastrophic consequences instead
of being catched and signalled in an orderly fashion.
(3) Any modifications of the container type lead to a review of
all code that uses that container since the rules change from
container to container. Iterators that worked could be invalid
now. This another source of errors.
This makes C++ marginally faster than what I am writing. In several
million instructions C++ will save maybe a few hundred instructions.
Nothing really important. In my opinion, less brittle softawre is
better than extremely fast one that breaks and crashes at the slightest
problem.
But this is (again) a personal point of view.
Thanks for your input.
jacob