write that they are less dangerous. So what should I do now?
container, but not remove elements. I need to iterate through the
to access elements directly. Thus, a container which allows fast access
nice.
key and a pair of classname and featurevector as map-entry. What would
Robbie Hatley wrote:
"silversurfer" <kietzi@web.de> wrote:
Ok, this should be fairly easy for most of you (at least I hope so),
but not for me:
Let us say we have got the following elements:
std::vector<Entry> models; //Entry is a struct
std::vector<Entry>::iterator modelIterator;
In a method, I am currently writing, I need to get a pointer to an
entry in the vector.
No you don't. Don't use pointers to elements in Vectors.
Pointers to elements in vectors tend to get "stale", because
vectors reallocate themselves if they grow, so you'd eventually
end up dereferencing wild pointers and crashing your program.
Your reasoning is flawed, insofar as it creates no distinction between
a pointer-to-element and an iterator. Both will be invalidated under
the same conditions.
Furthermore, there may very well be a valid reason to take the address
of an element of a container. For example, one might wish to call a
function which uses a pointer type as an output parameter. I would not
advocate writing such a function, but in practice one frequently has
unpleasant interfaces foisted.
Of course it doesn't work. The return type of your function is:
Entry*
but the type of tmpEntry is:
std::vector<Entry>::iterator
The two types are not even remotely similar.
That's a bit of an overstatement. They support a nearly identical set
of operations, and one is a conceptual generalization of the other.
What is the case is that they are not convertible to one another.
I do not really understand this: As far as I understood it,
an iterator should be a pointer to the elements of the vector,
An iterator is not a pointer. It might (or might not) be
IMPLIMENTED in terms of a pointer, but unless you're writing
a compiler, that's none of your business.
But stating that "iterators are generalized pointers," with appropriate
follow-up explanation, can be a helpful way of explaining what
iterators are, how they work, and why they exist.
An iterator can (and should) be USED LIKE a pointer, yes.
In most ways, but not all. For example, it cannot be used as the
lvalue of an assignment statement taking a pointer rvalue.
How can I get a pointer to the element to which the iterator
is currently pointing?
If you absolutely MUST do that, then you can, easily, like so:
Entry* DangerousPointer = &(*modelIterator);
But that is very dangerous.
In what sense? As I've mentioned, an iterator will be invalidated just
as often as a pointer-to-element (I can't say this with 100% certainty
without referring to the standard, but I believe this is at least the
case in practice). I suppose you could try to delete it or something,
but I'd say the dangerous part is trying to delete a pointer you don't
own, not having the pointer in the first place.
What I *would* say is that it's inelegant and unlikely to be necessary.
Inelegance is the pain we feel so that we can notice design problems,
and unnecessary code is a good way to ask for trouble.
For iterating through the elements
of a Vector, use real iterators. You can use iterators for (almost)
anything you could use pointers for.
Yes. Better yet, use standard algorithms such as std::for_each() most
of the time. The benefits of iterators compound and multiply the more
widely they're used. For example, a function which populates a
container will be more efficient if it takes an output iterator as a
parameter, rather than returning the container by value. It's just
good to establish habits like that.
Or use integer subscripting. With vectors, that's often easier than
using iterators, and you don't need to worry about whether an old
iterator still points to something valid.
I disagree with this suggestion, for two reasons.
First, it is inadvisable to couple oneself to a more restrictive
interface than one needs. If all you're doing is iterating across the
elements of a container in forward order, then all you need is for the
container to be a model of Forward Sequence. If you write code that
implements that iteration in terms of integer subscripting, you place
the additional requirement that the container be a model of Random
Access Sequence. That means you can't change your mind and use a
different Forward Sequence without changing all your looping code.
Second, even though it's safe in the context of a canonically-written
for-loop, std::vector::operator[]() is unsafe in general because it
does not check the validity of the index. The checked version,
std::vector::at(), is safer but of course incurs additional runtime
overhead, as well as throwing an exception. Such is the cost of random
access. The problem with using it even in a loop that's safe is that
maybe some day someone moves that code around and it's not safe
anymore, or they see you doing it and copy what you're doing without
understanding how to make it safe.
So, maybe it's easier to write, but it introduces too many potential
maintenance complications to justify such trivial expediency.
Iterators are more explicit, less dangerous, and less restrictive.
Luke