 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Angelo Guest
|
Posted: Thu Sep 15, 2005 1:12 am Post subject: question about iterators |
|
|
Hello, I was working with a list and came upon an issue with iterators.
I dont fully understand how it works, so Im asking here. Here's a code
snipet.
// function declaration
void StoreA( MyObject* pP );
// MyObject is a simple class
void main()
{
std::list<MyObject>A;
MyObject a;
MyObject b;
MyObject.push_back( a );
MyObject.push_back( b );
for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
}
How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
Thanks in advance
Angelo
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gerhard Menzl Guest
|
Posted: Thu Sep 15, 2005 9:05 am Post subject: Re: question about iterators |
|
|
Angelo wrote:
| Quote: | void StoreA( MyObject* pP );
// MyObject is a simple class
void main()
{
std::list<MyObject>A;
MyObject a;
MyObject b;
MyObject.push_back( a );
MyObject.push_back( b );
for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
}
How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
|
The answer is simple: iterators are not pointers. StoreA() takes a
MyObject*, hence you cannot pass it a std::list<MyObject>::iterator.
They are different types. C++ Standard Library iterators support a
narrow interface: copying, dereferencing (to get at the container
element), incrementing (to move forward), comparison for equality.
Certain iterator types also support assignment, decrementing (to move
backward), and iterator arithmetics. That's about it. It promises no
such thing as an implicit conversion to pointer to element type.
The confusion may arise because some implementations of std::vector
define iterators as simple pointers, but this is an implementation
detail you cannot rely upon. Even for vectors, the only portable way to
obtain the address of an element is &*it.
--
Gerhard Menzl
#dogma int main ()
Humans may reply by replacing the thermal post part of my e-mail address
with "kapsch" and the top level domain part with "net".
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
albrecht.fritzsche Guest
|
Posted: Thu Sep 15, 2005 9:05 am Post subject: Re: question about iterators |
|
|
Angelo wrote:
| Quote: | Hello, I was working with a list and came upon an issue with iterators.
I dont fully understand how it works, so Im asking here. Here's a code
snipet.
// function declaration
void StoreA( MyObject* pP );
|
Why don't you choose
void StoreA(MyObject&); // or even (const MyObject&)
? THis would make your code easier (and safer).
| Quote: |
// MyObject is a simple class
void main()
{
std::list<MyObject>A;
MyObject a;
MyObject b;
MyObject.push_back( a );
MyObject.push_back( b );
|
probably you mean A here instead of MyObject?
| Quote: | for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
|
probably it is a list iterator?
Ok, *it a call to the list iterator's operator*(), which every
iterator has to implement to get access to the element the iterator
points to. It will return either a
const MyObject& or MyObject&
If your StoreA() function would had been as I've proposed above this
line would had changed into
StoreA(*it);
Since your StoreA() function requires a pointer to a MyObject but
your list stores elements of type MyObject you have to dereference
the object the iterator is pointing at.
| Quote: | How come I must de-reference and then get the pointer to the iterator
for this to work?
|
As described - due to your selection of
StoreA(MyObject*) vs list<MyObject>
^^^^^^^^^ ^^^^^^^^
ie, pointer vs non-pointer type. If you can agree on one type
then the additional type transformation is not required.
Ali
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Daniel Krügler Guest
|
Posted: Thu Sep 15, 2005 9:06 am Post subject: Re: question about iterators |
|
|
Hello Angelo,
Angelo wrote:
| Quote: | Hello, I was working with a list and came upon an issue with iterators.
I dont fully understand how it works, so Im asking here. Here's a code
snipet.
// function declaration
void StoreA( MyObject* pP );
|
In the light of the following text I **propose** that you either change
the signature of StoreA to
void StoreA( const MyObject& pP );
if StoreA is not intended to modify the given argument or
void StoreA( MyObject& pP );
is it will modify its argument. (Performing these changes will lead to
the new loop
for (it=A.begin(); it!=As.end(); ++it )
StoreA( *it );
)
But read further...
This is not a valid signature of main. Use
int main()
instead.
| Quote: | std::list<MyObject>A;
MyObject a;
MyObject b;
MyObject.push_back( a );
MyObject.push_back( b );
for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
}
How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
|
Iterators are more general than pointers. They provide a pointer-like
interface (or a subset thereof, depending on their category) but
need not to be a real pointer - but any pointer **is** an iterator!
This has nothing to do with inheritance, but is a concept, which
provides an interface contract.
Most probably the iterator of std::list is a class which allows
traversal along the list nodes, so assume that this iterator is of the
following type (modulo possible template parameters):
class internal_list_iterator {
...
public:
// Must be copyable:
internal_list_iterator(const internal_list_iterator&);
// ... and assignable:
internal_list_iterator& operator=(const internal_list_iterator&);
// Must be prefix-incrementable:
internal_list_iterator& operator++();
// Allows access to hosted value_type:
reference operator*() const;
... // Comparison and other operations omitted for clarity
};
std::list::begin()/end() will return an instance of such class.
Now you should see that 'it', which is of type internal_list_iterator,
is not convertible to *value_type (which is *MyObject in your case)
and thus dereferencing the iterator first (to obtain &MyObject) is
necessary to get an object pointer of MyObject.
Hope that helps,
Daniel Krügler
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ulrich Eckhardt Guest
|
Posted: Thu Sep 15, 2005 9:08 am Post subject: Re: question about iterators |
|
|
Angelo wrote:
| Quote: | // function declaration
void StoreA( MyObject* pP );
[...]
for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net).
|
'it' is an iterator, not a pointer, and it is also not convertible to a
pointer. What you can do is invoke its operator* overload, which gives you
a reference to the element of the list that the iterator points to, and
then use & to get the address thereof.
Uli
--
Questions ?
see C++-FAQ Lite: http://parashift.com/c++-faq-lite/ first !
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
jrm Guest
|
Posted: Thu Sep 15, 2005 9:09 am Post subject: Re: question about iterators |
|
|
For most std. containers, iterators are implemented as classes similar
to the one described in 'Design Pattern' book - 'Iterator' pattern.
So in your example above, A.begin() returns an iterator of type
std::list<MyObject>::iterator (I am assuming it is not const as
StoreA() seems to take a pointer to a non-const object), and these
iterator classes usually implement 'operator * ()' that returns a
reference to the object in the container.
Here are the gory details for std::list from the libstdc++ site:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/libstdc%2b%2b-v3/include/bits/stl_list.h?rev=1.51.2.1&content-type=text/x-cvsweb-markup
Hope this helps.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Meador Inge Guest
|
Posted: Thu Sep 15, 2005 9:10 am Post subject: Re: question about iterators |
|
|
Angelo wrote:
| Quote: | How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
|
C++ style iterators are designed to have an interface similar to that
of C and C++ pointers, but the two are not strictly the same. A C++
style iterator is an abstraction used to hold the location of a
particular object in a container. An iterator defines the dereference
operator (e.g., the iterator class defines operator*) to return the
object in the location that it references. Thus the value of an
iterator locating an object and the address of the object are not
necessarily equal. This explains why you have to use '&(*p)' to get the
address of the object currently referenced by the iterator: the '*'
returns the object the iterator references and the '&' returns the
address of the object returned by operator*.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Thu Sep 15, 2005 10:15 am Post subject: Re: question about iterators |
|
|
Angelo wrote:
| Quote: | Hello, I was working with a list and came upon an issue with
iterators. I dont fully understand how it works, so Im asking
here. Here's a code snipet.
// function declaration
void StoreA( MyObject* pP );
// MyObject is a simple class
void main()
|
Just in passing, the return type of main() is required by the
standard to be int. Some compilers enforce this. (The standard
requires a diagnostic in this case.)
| Quote: | {
std::list<MyObject>A;
MyObject a;
MyObject b;
MyObject.push_back( a );
MyObject.push_back( b );
for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
}
How come I must de-reference and then get the pointer to the
iterator for this to work?
|
Because you have to pass a MyObject* to StoreA.
| Quote: | The compiler kept giving errors without this(and it took some
time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
|
Nothing. Like everything else, they have a type. MyObject* is
one type. std::list<MyObject>::iterator is another. If a
function expects a MyObject*, you can't pass it a
std::list<MyObject>::iterator, and vice versa. If an implicit
conversion exists (it doesn't here), the compiler will use it.
If it doesn't you have to do something explicit to get the
desired type.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Julien Lamy Guest
|
Posted: Thu Sep 15, 2005 10:17 am Post subject: Re: question about iterators |
|
|
Angelo a écrit :
| Quote: | // function declaration
void StoreA( MyObject* pP );
// MyObject is a simple class
void main()
{
std::list<MyObject>A;
MyObject a;
MyObject b;
MyObject.push_back( a );
MyObject.push_back( b );
for (it=A.begin(); it!=As.end(); ++it )
StoreA( &(*it) );
^^^^^^
}
How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
|
Iterators behave like pointers (i.e. you can do ++it, --it, *it and so
on), but iterators are generally _not_ pointers.
The type of your iterator is std::list<MyObject>::iterator, so you can't
directly feed it to your StoreA function, which expects a MyObject*. You
must first get the MyObject the iterator "points" to, and then get a
pointer to that object, hence the expression &(*it).
Now, does your StoreA function really need a pointer, or can it do with
a reference ? If it can work with a reference, the call will be simpler :
void StoreA( MyObject & obj );
std::list<MyObject> A;
// fill the list
std::list<MyObject>::iterator it = A.begin();
StoreA(*it);
HTH,
--
Julien Lamy
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
M Jared Finder Guest
|
Posted: Thu Sep 15, 2005 10:18 am Post subject: Re: question about iterators |
|
|
Angelo wrote:
<snip>
| Quote: | How come I must de-reference and then get the pointer to the iterator
for this to work? The compiler kept giving errors without this(and it
took some time to find info on this on the net). On regular pointers,
this would be a redundancy:
eg.
int *p;
&(*p) is the same as p
what's so special about iterators?
|
In other words, "Why aren't the standard iterators implicitly
convertible to pointers to the object they refer to?"
Implicit conversions are dangerous because they happen without being
asked for. The presence of them also makes function overload resolution
act in ways that even C++ experts get confused by.
While I don't see anything particularly bad about allowing an implicit
conversion of iterator<T> to T*, I try to stay away from implicit
conversions unless I see a huge benefit to providing one. My guess is
the C++ standard committee feels similarly.
Also, this would be impossible to do for iterators that don't refer to
objects, like the kind returned by back_inserter. I've always felt that
making back_inserter an iterator was a bad hack (I dislike any iterator
simpler than a forward iterator), but it is in the library, so it must
be considered.
-- MJF
-- MJF
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Yuri Khan Guest
|
Posted: Fri Sep 16, 2005 12:24 pm Post subject: Re: question about iterators |
|
|
M Jared Finder wrote:
| Quote: | While I don't see anything particularly bad about allowing an implicit
conversion of iterator<T> to T*, I try to stay away from implicit
conversions unless I see a huge benefit to providing one. My guess is
the C++ standard committee feels similarly.
|
Suppose you have a std::list<T>::iterator. Generally, it is a
bidirectional iterator, that does not provide iterator arithmetics like
(it + d) or indexed access like it[d].
Suppose now that this std::list<T>::iterator is implicitly convertible
to T*. Suddenly, (it + d) means ((it.operator T*)() + d) and it[d]
means *((it.operator T*)() + d). Now, std::list typically stores its
elements one-by-one in separately allocated nodes, so doing pointer
arithmetics on pointers to list elements is a big no-no, according to
Chapter 5.7, Verse 5.
So you accidentally pass a couple of list iterators to an algorithm
that requires random access iterators, and instead of giving you a
compilation error, the compiler happily compiles nonsense. If you're
lucky, your program will dump core once it tries to access memory
beyond the list node. More likely, it will trash the free store and you
will get inexplicable strange effects ranging from incorrect values in
other data structures to heap corruption, possibly with remote code
execution.
So conversion of arbitrary iterators to pointers is a dangerous
operation, and, as such, must be performed explicitly with great care.
By writing "&*it", you say, "I understand the possible implications of
converting this iterator to a pointer, and I assume full responsibility
for any and all effects resulting from it."
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Angelo Guest
|
Posted: Fri Sep 16, 2005 3:54 pm Post subject: Re: question about iterators |
|
|
thanks everybody for the help. I understand it much better now.
-Iterators are container classes. * operator has been overloaded to
return a reference that the iterator contains.
When I was working on the program, I had a tough time finding howto get
a reference to the object the iterator contained ( the overloaded *)
and I thought that it looked odd doing &(*it) to get a ptr to the
object.
Also, I am going to change my function to use references instead of
ptrs to objects.
btw -- sorry for the sloppy code, I had just finished a project and was
quite tired and 'dizzy'.
Angelo
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|