Concerning STL iterators

Discussion in 'C++' started by pvonnied@gmail.com, Nov 21, 2006.

  1. Guest

    Hi,

    Once more a question (sorry for the different e-mail addresses [in
    regard
    to my other posts], here @ work we have to use Google to post to
    newsgroups):

    If I use an iterator, say from std::map, I initialize it like so:
    <--- --->
    std::map<int, myClass*> myCollection;
    std::map<int, myClass*>::iterator it = myCollection.begin();
    for(; it != myCollection.begin(); ++it) { // do something }
    ---><---

    For which reasons C++ uses the syntax above (I guess
    because we use templates) ? Why is it not possible to
    use myCollection.iterator it = myCollection.begin(); like
    a kind of an inner class (Java style...)?

    That would eliminate the need to retype std::map<int, myClass*>...
    just to get an iterator. I know that I could use a typedef...

    Binary regards (as one suggested in stead of my Brgds tag ;-) ),
    Peter
    , Nov 21, 2006
    #1
    1. Advertising

  2. mlimber Guest

    wrote:
    > If I use an iterator, say from std::map, I initialize it like so:
    > <--- --->
    > std::map<int, myClass*> myCollection;


    You probably want to use some sort of smart pointer rather than a bald
    pointer for exception-safety and ease of use (see
    http://www.artima.com/cppsource/bigtwo.html).

    > std::map<int, myClass*>::iterator it = myCollection.begin();
    > for(; it != myCollection.begin(); ++it) { // do something }


    You probably meant myCollection.end() on the last line. The more
    idiomatic way is:

    typedef std::map<int, myClass*>::iterator Iter;
    const Iter end = myCollection.end();
    for( Iter it=myCollection.begin(); it != end; ++it)
    { // do something }

    or

    typedef std::map<int, myClass*>::iterator Iter;
    for( Iter it=myCollection.begin(), end = myCollection.end(); it !=
    end; ++it)
    { // do something }

    or even

    for_each( myCollection.begin(), myCollection.end(), /*something*/ );

    > ---><---
    >
    > For which reasons C++ uses the syntax above (I guess
    > because we use templates) ?


    Which syntax in particular?

    > Why is it not possible to
    > use myCollection.iterator it = myCollection.begin(); like
    > a kind of an inner class (Java style...)?


    Because this is not Java? It's because C++ has a distinct member access
    operator (.) and a scope operator :):) -- not to mention ->. For why
    this is so, you'll want to consult Stroustrup's _Design and Evolution
    of C++_ (which I'm not sure actually discusses it) or just deal with
    it.

    > That would eliminate the need to retype std::map<int, myClass*>...
    > just to get an iterator. I know that I could use a typedef...


    If you know the answer, stop being lazy. ;-)

    Cheers! --M
    mlimber, Nov 21, 2006
    #2
    1. Advertising

  3. wrote:

    > Why is it not possible to
    > use myCollection.iterator it = myCollection.begin(); like
    > a kind of an inner class (Java style...)?


    Because member types are static members and don't depend on the bound
    object.


    > That would eliminate the need to retype std::map<int, myClass*>...
    > just to get an iterator.


    This will be removed in C++0x with the new type interence related keywords.
    Mathias Gaunard, Nov 21, 2006
    #3
  4. dasjotre Guest

    wrote:
    > Hi,
    >
    > Once more a question (sorry for the different e-mail addresses [in
    > regard
    > to my other posts], here @ work we have to use Google to post to
    > newsgroups):
    >
    > If I use an iterator, say from std::map, I initialize it like so:
    > <--- --->
    > std::map<int, myClass*> myCollection;
    > std::map<int, myClass*>::iterator it = myCollection.begin();
    > for(; it != myCollection.begin(); ++it) { // do something }
    > ---><---
    >
    > For which reasons C++ uses the syntax above (I guess
    > because we use templates) ? Why is it not possible to
    > use myCollection.iterator it = myCollection.begin(); like
    > a kind of an inner class (Java style...)?
    >


    :: is a scope operator and it works on types
    or namespaces, not objects. Dot operator
    works on objects (instances).

    in C++ you can have a construct like this

    struct C
    {
    // type
    struct inner_C {};
    // member with the same name
    int inner_C;
    };

    so

    C::inner_C

    references the type inner_C and

    C c;
    c.inner_C

    references an int member inner_C of object c.

    Why is it that way? Because standard says so ;)

    > That would eliminate the need to retype std::map<int, myClass*>...
    > just to get an iterator. I know that I could use a typedef...
    >


    typedef is the solution.
    dasjotre, Nov 21, 2006
    #4
  5. Pete Becker Guest

    wrote:
    > Hi,
    >
    > Once more a question (sorry for the different e-mail addresses [in
    > regard
    > to my other posts], here @ work we have to use Google to post to
    > newsgroups):
    >
    > If I use an iterator, say from std::map, I initialize it like so:
    > <--- --->
    > std::map<int, myClass*> myCollection;
    > std::map<int, myClass*>::iterator it = myCollection.begin();
    > for(; it != myCollection.begin(); ++it) { // do something }
    > ---><---
    >
    > For which reasons C++ uses the syntax above (I guess
    > because we use templates) ? Why is it not possible to
    > use myCollection.iterator it = myCollection.begin(); like
    > a kind of an inner class (Java style...)?
    >


    Because Java's iterators are different from C++'s iterators. In C++, an
    iterator designates one end of a range of elements. You use a pair of
    iterators to designate a range: one to mark the beginning, and one to
    mark the end. That gives you a great deal more flexibility than
    combining both ends into a single object.

    > That would eliminate the need to retype std::map<int, myClass*>...
    > just to get an iterator. I know that I could use a typedef...
    >


    Ordinarily, iterators are passed to algorithms:

    std::map<int, myClass*> myCollection;
    // do something to populate myCollection
    algorithm(myCollection.begin(), myCollection.end());

    Where algorithm is a template function that takes two iterators of the
    same type:

    template <class Iter>
    void algorithm(Iter first, Iter last)
    {
    while (first != last)
    do_something_with *first++;
    }

    Code that creates auto objects that hold iterators is non-idiomatic, so
    it tends to be more awkward. But if you can't hoist that for loop out
    into a separate function, then you have to write the name of the
    iterator's type.

    There's help coming, though: in C++0x there will probably be automatic
    type detection, so that you can define a local variable whose type is
    the same as its initializer, without having to write the type explicitly.

    --

    -- Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com)
    Author of "The Standard C++ Library Extensions: a Tutorial and
    Reference." (www.petebecker.com/tr1book)
    Pete Becker, Nov 21, 2006
    #5
  6. kwikius Guest

    Mathias Gaunard wrote:
    > wrote:
    >
    > > Why is it not possible to
    > > use myCollection.iterator it = myCollection.begin(); like
    > > a kind of an inner class (Java style...)?

    >
    > Because member types are static members and don't depend on the bound
    > object.
    >
    >
    > > That would eliminate the need to retype std::map<int, myClass*>...
    > > just to get an iterator.

    >
    > This will be removed in C++0x with the new type interence related keywords.


    I got a feeling that progress on that stalled though it sure will be a
    bit sad if that doesnt happen.

    regards
    Andy Little
    kwikius, Nov 21, 2006
    #6
  7. Salt_Peter Guest

    wrote:
    > Hi,
    >
    > Once more a question (sorry for the different e-mail addresses [in
    > regard
    > to my other posts], here @ work we have to use Google to post to
    > newsgroups):
    >
    > If I use an iterator, say from std::map, I initialize it like so:
    > <--- --->
    > std::map<int, myClass*> myCollection;
    > std::map<int, myClass*>::iterator it = myCollection.begin();
    > for(; it != myCollection.begin(); ++it) { // do something }
    > ---><---
    >
    > For which reasons C++ uses the syntax above (I guess
    > because we use templates) ? Why is it not possible to
    > use myCollection.iterator it = myCollection.begin(); like
    > a kind of an inner class (Java style...)?
    >
    > That would eliminate the need to retype std::map<int, myClass*>...
    > just to get an iterator. I know that I could use a typedef...
    >
    > Binary regards (as one suggested in stead of my Brgds tag ;-) ),
    > Peter


    Whats preventing you from doing so? Since this is a std::map?
    Its your choice if you choose to expose iterators or to embed an
    iterator class.
    You only need to insure any exposed iterator is reset appropriately.
    Note that resetting iterators is not neccessarily a costly operation
    since you could, say, provide an overloaded swap(...) member function
    that works with other containers.

    #include <iostream>
    #include <map>

    template< typename T, typename P >
    class Container
    {
    typedef typename std::map< const T, const P* const > MapType;
    typedef typename MapType::iterator IterType;
    MapType themap;
    public:
    IterType iter_begin;
    IterType iter_end;
    IterType iter;
    // lifecycle
    Container() : themap(),
    iter_begin(themap.begin()),
    iter_end(themap.end()),
    iter()
    {
    }
    Container(const Container& copy)
    {
    std::swap(copy.themap, themap);
    iter_begin = themap.begin();
    iter_end = themap.end();
    }
    void insert(const T& r_t, const P* const ptr_m)
    {
    themap.insert(std::make_pair(r_t, ptr_m));
    iter_begin = themap.begin();
    iter_end = themap.end();
    }
    };

    struct MyClass
    {
    int n;
    };

    int main()
    {
    const MyClass array[] = {{0},{1},{2},{3},{4}};
    Container< int, MyClass > container;
    for( size_t i = 0; i < sizeof(array)/sizeof(MyClass); ++i)
    {
    container.insert(static_cast<int>(i), &array);
    }
    for( container.iter = container.iter_begin;
    container.iter != container.iter_end;
    ++container.iter )
    {
    // do whatever
    }
    }
    Salt_Peter, Nov 21, 2006
    #7
  8. Salt_Peter wrote:

    > Container(const Container& copy)
    > {
    > std::swap(copy.themap, themap);



    Copying is the same as swapping now?
    Mathias Gaunard, Nov 21, 2006
    #8
  9. Salt_Peter Guest

    Mathias Gaunard wrote:
    > Salt_Peter wrote:
    >
    > > Container(const Container& copy)
    > > {
    > > std::swap(copy.themap, themap);

    >
    >
    > Copying is the same as swapping now?


    I'm brain-dead today.
    Salt_Peter, Nov 21, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. onion_skin
    Replies:
    9
    Views:
    981
    Gavin Deane
    Jun 26, 2003
  2. Rusty

    STL iterators

    Rusty, Nov 27, 2003, in forum: C++
    Replies:
    1
    Views:
    293
    Matt S Trentini
    Nov 29, 2003
  3. Merlin
    Replies:
    4
    Views:
    587
    Merlin
    Apr 30, 2004
  4. Marcin Kaliciñski

    Iterators and reverse iterators

    Marcin Kaliciñski, May 8, 2005, in forum: C++
    Replies:
    1
    Views:
    475
    Kai-Uwe Bux
    May 8, 2005
  5. , India
    Replies:
    10
    Views:
    1,057
    James Kanze
    Aug 8, 2009
Loading...

Share This Page