Comma operator in for loop

Discussion in 'C++' started by Ralf Goertz, Sep 24, 2010.

  1. Ralf Goertz

    Ralf Goertz Guest

    Hi,

    I guess I don't really understand the concept of commas as sequence
    points but now I am in a position where I might have use for the comma
    in a statement other than a declaration. Is the following legal:


    #include <iostream>
    #include <set>

    using namespace std;


    int main() {
    set<unsigned> s;
    s.insert(42);
    s.insert(84);
    set<unsigned>::iterator i;
    for (i=s.begin(),++i;i!=s.end();++i)
    cout<<*i<<endl;
    return 0;
    }

    It compiles and does what I want, but it could still be undefined
    behaviour. So is it okay to use ",++i" before the first ";" of the
    for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    loop?
     
    Ralf Goertz, Sep 24, 2010
    #1
    1. Advertising

  2. On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    > I guess I don't really understand the concept of commas as sequence
    > points but now I am in a position where I might have use for the comma
    > in a statement other than a declaration. Is the following legal:
    >
    >
    > #include<iostream>
    > #include<set>
    >
    > using namespace std;
    >
    >
    > int main() {
    > set<unsigned> s;
    > s.insert(42);
    > s.insert(84);
    > set<unsigned>::iterator i;
    > for (i=s.begin(),++i;i!=s.end();++i)
    > cout<<*i<<endl;
    > return 0;
    > }
    >
    > It compiles and does what I want, but it could still be undefined
    > behaviour. So is it okay to use ",++i" before the first ";" of the
    > for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    > loop?


    It seems fine, and if it does what you need, keep it. If you just
    needed to skip the first element, I'd probably do

    i = ++(s.begin());

    The call to 'begin' yields a temporary iterator, which you can increment
    (provided the container is not empty), and then assign the value to the
    'i'. The only danger is that you really cannot do the increment if the
    container is empty.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Sep 24, 2010
    #2
    1. Advertising

  3. Ralf Goertz

    Marc Guest

    Victor Bazarov wrote:

    > ++(s.begin())


    Although it works here (s is a set, so the iterator can hardly be a
    basic type like a pointer), I believe it is a good habit to use
    boost::next and pretend the signature of operator++ is:
    Iterator& operator++()&; // C++0x
     
    Marc, Sep 24, 2010
    #3
  4. Victor Bazarov wrote:
    > On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    >> I guess I don't really understand the concept of commas as sequence
    >> points but now I am in a position where I might have use for the comma
    >> in a statement other than a declaration. Is the following legal:
    >>
    >>
    >> #include<iostream>
    >> #include<set>
    >>
    >> using namespace std;
    >>
    >>
    >> int main() {
    >> set<unsigned> s;
    >> s.insert(42);
    >> s.insert(84);
    >> set<unsigned>::iterator i;
    >> for (i=s.begin(),++i;i!=s.end();++i)
    >> cout<<*i<<endl;
    >> return 0;
    >> }
    >>
    >> It compiles and does what I want, but it could still be undefined
    >> behaviour. So is it okay to use ",++i" before the first ";" of the
    >> for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    >> loop?

    >
    > It seems fine, and if it does what you need, keep it. If you just
    > needed to skip the first element, I'd probably do
    >
    > i = ++(s.begin());


    I would do this:
    for (i=s.begin() + 1;i!=s.end();++i)
    cout<<*i<<endl;
    but it's not much different from your solution.

    >
    > The call to 'begin' yields a temporary iterator, which you can increment
    > (provided the container is not empty), and then assign the value to the
    > 'i'. The only danger is that you really cannot do the increment if the
    > container is empty.


    Yes, a check is missing, but I guess in the short example as above it is
    ok, since the set is not empty.
     
    Vladimir Jovic, Sep 24, 2010
    #4
  5. Ralf Goertz

    Ralf Goertz Guest

    Victor Bazarov wrote:

    > On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    >>
    >> It compiles and does what I want, but it could still be undefined
    >> behaviour. So is it okay to use ",++i" before the first ";" of the
    >> for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    >> loop?

    >
    > It seems fine, and if it does what you need, keep it. If you just
    > needed to skip the first element, I'd probably do
    >
    > i = ++(s.begin());


    Okay, that's better since it allows me to define i in the loop.

    > The call to 'begin' yields a temporary iterator, which you can increment
    > (provided the container is not empty), and then assign the value to the
    > 'i'. The only danger is that you really cannot do the increment if
    > the container is empty.


    I think I can be pretty sure that s is not empty as it is in an
    unordered_map<unsigned, set<unsigned> > m, and elements get inserted
    into m by means of m[4711].insert(42) only.

    Thanks,

    Ralf
     
    Ralf Goertz, Sep 24, 2010
    #5
  6. Ralf Goertz

    Ralf Goertz Guest

    Vladimir Jovic wrote:

    > Victor Bazarov wrote:
    >> On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    >>> I guess I don't really understand the concept of commas as sequence
    >>> points but now I am in a position where I might have use for the comma
    >>> in a statement other than a declaration. Is the following legal:
    >>>
    >>>
    >>> #include<iostream>
    >>> #include<set>
    >>>
    >>> using namespace std;
    >>>
    >>>
    >>> int main() {
    >>> set<unsigned> s;
    >>> s.insert(42);
    >>> s.insert(84);
    >>> set<unsigned>::iterator i;
    >>> for (i=s.begin(),++i;i!=s.end();++i)
    >>> cout<<*i<<endl;
    >>> return 0;
    >>> }
    >>>
    >>> It compiles and does what I want, but it could still be undefined
    >>> behaviour. So is it okay to use ",++i" before the first ";" of the
    >>> for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    >>> loop?

    >>
    >> It seems fine, and if it does what you need, keep it. If you just
    >> needed to skip the first element, I'd probably do
    >>
    >> i = ++(s.begin());

    >
    > I would do this:
    > for (i=s.begin() + 1;i!=s.end();++i)
    > cout<<*i<<endl;
    > but it's not much different from your solution.


    That was my first idea, but it doesn't compile:

    error: no match for 'operator+' in 's.std::set<_Key, _Compare, _Alloc>:
    :begin [with _Key = unsigned int, _Compare = std::less<unsigned int>, _Alloc = s
    td::allocator<unsigned int>]() + 1'
     
    Ralf Goertz, Sep 24, 2010
    #6
  7. On 9/24/2010 9:11 AM, Ralf Goertz wrote:
    > Vladimir Jovic wrote:
    >
    >> Victor Bazarov wrote:
    >>> On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    >>>> I guess I don't really understand the concept of commas as sequence
    >>>> points but now I am in a position where I might have use for the comma
    >>>> in a statement other than a declaration. Is the following legal:
    >>>>
    >>>>
    >>>> #include<iostream>
    >>>> #include<set>
    >>>>
    >>>> using namespace std;
    >>>>
    >>>>
    >>>> int main() {
    >>>> set<unsigned> s;
    >>>> s.insert(42);
    >>>> s.insert(84);
    >>>> set<unsigned>::iterator i;
    >>>> for (i=s.begin(),++i;i!=s.end();++i)
    >>>> cout<<*i<<endl;
    >>>> return 0;
    >>>> }
    >>>>
    >>>> It compiles and does what I want, but it could still be undefined
    >>>> behaviour. So is it okay to use ",++i" before the first ";" of the
    >>>> for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    >>>> loop?
    >>>
    >>> It seems fine, and if it does what you need, keep it. If you just
    >>> needed to skip the first element, I'd probably do
    >>>
    >>> i = ++(s.begin());

    >>
    >> I would do this:
    >> for (i=s.begin() + 1;i!=s.end();++i)
    >> cout<<*i<<endl;
    >> but it's not much different from your solution.

    >
    > That was my first idea, but it doesn't compile:
    >
    > error: no match for 'operator+' in 's.std::set<_Key, _Compare, _Alloc>:
    > :begin [with _Key = unsigned int, _Compare = std::less<unsigned int>, _Alloc = s
    > td::allocator<unsigned int>]() + 1'


    The set iterator is not of the random-access kind, you cannot add a
    number to it.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Sep 24, 2010
    #7
  8. Ralf Goertz wrote:
    > Vladimir Jovic wrote:
    >
    >> Victor Bazarov wrote:
    >>> On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    >>>> I guess I don't really understand the concept of commas as sequence
    >>>> points but now I am in a position where I might have use for the comma
    >>>> in a statement other than a declaration. Is the following legal:
    >>>>
    >>>>
    >>>> #include<iostream>
    >>>> #include<set>
    >>>>
    >>>> using namespace std;
    >>>>
    >>>>
    >>>> int main() {
    >>>> set<unsigned> s;
    >>>> s.insert(42);
    >>>> s.insert(84);
    >>>> set<unsigned>::iterator i;
    >>>> for (i=s.begin(),++i;i!=s.end();++i)
    >>>> cout<<*i<<endl;
    >>>> return 0;
    >>>> }
    >>>>
    >>>> It compiles and does what I want, but it could still be undefined
    >>>> behaviour. So is it okay to use ",++i" before the first ";" of the
    >>>> for-loop, or is it saver to check for i!=s.begin() in the *body* of the
    >>>> loop?
    >>> It seems fine, and if it does what you need, keep it. If you just
    >>> needed to skip the first element, I'd probably do
    >>>
    >>> i = ++(s.begin());

    >> I would do this:
    >> for (i=s.begin() + 1;i!=s.end();++i)
    >> cout<<*i<<endl;
    >> but it's not much different from your solution.

    >
    > That was my first idea, but it doesn't compile:
    >
    > error: no match for 'operator+' in 's.std::set<_Key, _Compare, _Alloc>:
    > :begin [with _Key = unsigned int, _Compare = std::less<unsigned int>, _Alloc = s
    > td::allocator<unsigned int>]() + 1'


    Yes, off course. set::begin() returns bidirectional iterator, which do
    not support arithmetic operations + and - :(
     
    Vladimir Jovic, Sep 24, 2010
    #8
  9. Ralf Goertz

    James Kanze Guest

    On Sep 24, 1:26 pm, Victor Bazarov <> wrote:
    > On 9/24/2010 5:13 AM, Ralf Goertz wrote:
    > > I guess I don't really understand the concept of commas as
    > > sequence points but now I am in a position where I might
    > > have use for the comma in a statement other than
    > > a declaration. Is the following legal:


    > > #include<iostream>
    > > #include<set>


    > > using namespace std;


    > > int main() {
    > > set<unsigned> s;
    > > s.insert(42);
    > > s.insert(84);
    > > set<unsigned>::iterator i;
    > > for (i=s.begin(),++i;i!=s.end();++i)
    > > cout<<*i<<endl;
    > > return 0;
    > > }


    > > It compiles and does what I want, but it could still be
    > > undefined behaviour. So is it okay to use ",++i" before the
    > > first ";" of the for-loop, or is it saver to check for
    > > i!=s.begin() in the *body* of the loop?


    > It seems fine, and if it does what you need, keep it. If you just
    > needed to skip the first element, I'd probably do


    > i = ++(s.begin());


    > The call to 'begin' yields a temporary iterator, which you can
    > increment (provided the container is not empty),


    And provided the implementation allows it. Normally, you cannot
    apply ++ to a temporary. For a user defined operator, however,
    the rules of function calls apply: if operator++ is a member,
    you can use it; if it is not, then you'd be binding a temporary
    to a reference---which is illegal.

    In practice, the need for such things occurs often enough that
    most people have a template function "next":

    template<typename ForwardIterator>
    ForwardIterator
    next(ForwardIterator original)
    {
    ++ original;
    return original;
    }

    and then use i = next(s.begin()).

    (Of course, none of this is valid if the container is empty.)

    --
    James Kanze
     
    James Kanze, Sep 24, 2010
    #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. Paul Davis
    Replies:
    7
    Views:
    598
    Paul Davis
    Jul 17, 2003
  2. Derek
    Replies:
    6
    Views:
    377
    Old Wolf
    Apr 13, 2004
  3. G Patel

    comma operator and assignment operator

    G Patel, Feb 7, 2005, in forum: C Programming
    Replies:
    4
    Views:
    492
    Barry Schwarz
    Feb 8, 2005
  4. Christina
    Replies:
    26
    Views:
    471
    Dave Anderson
    Feb 2, 2004
  5. Isaac Won
    Replies:
    9
    Views:
    383
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page