C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

question on the comma operator

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Lorenzo Bettini
Guest





PostPosted: Tue Aug 16, 2005 2:39 pm    Post subject: question on the comma operator Reply with quote



Hi

I've always used this macro in one of my program

#define foropt for (gengetopt_option_list::iterator it =
gengetopt_options.begin();
it != gengetopt_options.end(), opt = *it;
++it)

like this

gengetopt_option *opt

foropt
{
do something with opt
}

now with g++ (GCC) 4.0.1 (Debian 4.0.1-2)

the foropt loop always segfaults, because it goes one element too much
(thus the opt points to garbage). Why is this? It looks like the
expression "it != gengetopt_options.end()" is ignored...

I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);

but was the previous code wrong?

thanks in advance
Lorenzo

--
+-----------------------------------------------------+
Quote:
Lorenzo Bettini ICQ# lbetto, 16080134 |
PhD in Computer Science |
Dip. Sistemi e Informatica, Univ. di Firenze |
Florence - Italy (GNU/Linux User # 158233) |
Home Page : http://www.lorenzobettini.it |
http://music.dsi.unifi.it XKlaim language |
http://www.lorenzobettini.it/purple Cover Band |
http://www.gnu.org/software/src-highlite |
http://www.gnu.org/software/gengetopt |
http://www.lorenzobettini.it/software/gengen |
http://www.lorenzobettini.it/software/doublecpp |
+-----------------------------------------------------+


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Victor Bazarov
Guest





PostPosted: Tue Aug 16, 2005 6:03 pm    Post subject: Re: question on the comma operator Reply with quote



Lorenzo Bettini wrote:
Quote:
I've always used this macro in one of my program

#define foropt for (gengetopt_option_list::iterator it =
gengetopt_options.begin();
it != gengetopt_options.end(), opt = *it;
++it)

like this

gengetopt_option *opt

foropt
{
do something with opt
}

now with g++ (GCC) 4.0.1 (Debian 4.0.1-2)

the foropt loop always segfaults, because it goes one element too much
(thus the opt points to garbage). Why is this? It looks like the
expression "it != gengetopt_options.end()" is ignored...

I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);

but was the previous code wrong?

Yes, wrong. The comma operator evaluates its left operand, then has
a sequence point, then evaluates the right operand and the entire
expression has this last value. If you write

it != blah.end(), opt = *it

the expression most likely has undefined behaviour if the 'blah.end()'
iterator is not dereferenceable (which is most likely the case). This is
what happens: the "!=" is evaluated, then that value is _discarded_, then
the assignment is evaluated thus attempting to dereference 'it' which has
_already_ become invalid.

When you write

it != blah.end() && opt = *it

then if the 'not-equal' operator returns 'false', the right-hand side of
the '&&' is _not_ evaluated.

Generally speaking, if you don't intend to check the value of 'opt' as
well, the assignment should be moved to the third part of the 'for'
statement:

for ( ittype it = blah.begin(); it != blah.end(); opt = *it++ )
// ^^^^^^^^^^^

Which will ensure that (a) it only happens if 'it' can be dereferenced
and (b) that the condition does not rely on the 'opt' value for loop
termination. Of course, if 'opt' is a pointer _and_ you want to terminate
your loop not only if you finish the whole collection but also when you
encounter a null pointer among the elements, the '&&' you found should be
retained.

V

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Kyle
Guest





PostPosted: Tue Aug 16, 2005 11:32 pm    Post subject: Re: question on the comma operator Reply with quote



Lorenzo Bettini wrote:
Quote:
Hi

I've always used this macro in one of my program

#define foropt for (gengetopt_option_list::iterator it =
gengetopt_options.begin();
it != gengetopt_options.end(), opt = *it;
++it)

like this

gengetopt_option *opt

foropt
{
do something with opt
}

now with g++ (GCC) 4.0.1 (Debian 4.0.1-2)

the foropt loop always segfaults, because it goes one element too much
(thus the opt points to garbage). Why is this? It looks like the

quote from draft

"A pair of expressions separated by a comma is evaluated left to right
and the value of the left expression is discarded. ... The type and
value of the result are the type and value of the right operand"

Quote:
expression "it != gengetopt_options.end()" is ignored...

I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);

but was the previous code wrong?

thanks in advance
Lorenzo


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Thomas Richter
Guest





PostPosted: Tue Aug 16, 2005 11:33 pm    Post subject: Re: question on the comma operator Reply with quote

Hi,

Quote:
#define foropt for (gengetopt_option_list::iterator it =
gengetopt_options.begin();
it != gengetopt_options.end(), opt = *it;
++it)

like this

gengetopt_option *opt

foropt
{
do something with opt
}

now with g++ (GCC) 4.0.1 (Debian 4.0.1-2)

the foropt loop always segfaults, because it goes one element too much
(thus the opt points to garbage). Why is this? It looks like the
expression "it != gengetopt_options.end()" is ignored...

That, too:

it != gengetopt_options.end(), opt = *it

The comma operator evaluates its arguments left to right, no
matter what the result of the first statement is, i.e. there is no
"shortcutting" performed as it is done for && or || (&& evalulates
only its second argument if the first is true, || only if the first
is false). Thus, you deference an interator that is not pointing
to a valid object, and thus, the result is undefined. A segfault is
one out of several possible reactions. The final result of the operator,
is then the result of its second expression, that is, the result of
the comparison is, indeed, ignored.

General comment:
1) Some people might argue that you should have a good look at
<algorithms> and should try for_each() to iterate thru a container
like the above.
2) Even though I'm not a friend of for_each(), I would still believe
that making "opt" an argument of the macro would improve readability
a lot - no "hidden" names are required to be known by the reader
to understand the code.

Quote:
but was the previous code wrong?

I afraid so.

So long,
Thomas


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Tue Aug 16, 2005 11:34 pm    Post subject: Re: question on the comma operator Reply with quote

Hi Lorenzo,

Yes, the previous code was wrong. The comma operator performs the !=
test and ignores the result, proceeding to evaluate the assignment.
You'll find that doesn't work as a general idiom, as the types in the
comma-separated expression have to be the same, and it's only
coincidence that the pointer you're assigning can be implicitly
converted to int. The && form benefits from short-circuit evaluation,
is safe, and could be used.

For what it's worth, the code would be better expressed as:

for (gengetopt_option_list::iterat­or it =
gengetopt_options.begin();
it != gengetopt_options.end(); ++it)
{
gengetopt_option* opt = *it;
// ...
}

It's conventional to put macro names in all uppercase, but for
something simple that you'll only do once per program, better still to
avoid them completely.

Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Thomas Maeder
Guest





PostPosted: Tue Aug 16, 2005 11:35 pm    Post subject: Re: question on the comma operator Reply with quote

Lorenzo Bettini <bettini (AT) dsi (DOT) unifi.it> writes:

Quote:
I've always used this macro in one of my program

#define foropt for (gengetopt_option_list::iterator it =
gengetopt_options.begin();
it != gengetopt_options.end(), opt = *it;
++it)

Hmm. Macros are badly behaved beast. I prefer to use them very
reluctantly. And if I define one, I think that it should have a long,
uglyish name so that it stands out - this somewhat compensates for
macros not respecting most scopes.

foropt seems like a particularly bad name for a macro. Especially
since I don't really see what problem it solves.


Quote:
like this

gengetopt_option *opt

foropt
{
do something with opt
}

now with g++ (GCC) 4.0.1 (Debian 4.0.1-2)

the foropt loop always segfaults, because it goes one element too
much (thus the opt points to garbage). Why is this? It looks like
the expression "it != gengetopt_options.end()" is ignored...

That would be a bug.

Unless overloaded, the comma operator first evaluates the
sub-expression on the lefthand side, and then that on the righthand
side. It's value is the value of the sub-expression on the righthand
side.


Quote:
I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);

This will give you compiler errors for most types, because they won't
have the necessary implicit conversion. And if they have it, the
results will be surprising because the loop will stop where you don't
expect it to stop.

Why don't you simply write *it and it-> inside the loop?


Quote:
but was the previous code wrong?

Definitely.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
tony_in_da_uk@yahoo.co.uk
Guest





PostPosted: Wed Aug 17, 2005 10:00 am    Post subject: Re: question on the comma operator Reply with quote

Quote:
for ( ittype it = blah.begin(); it != blah.end(); opt = *it++ )

----------------------

That's not right, as opt is only assigned _after_ the first time
through the loop... - Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Martin Bonner
Guest





PostPosted: Wed Aug 17, 2005 2:35 pm    Post subject: Re: question on the comma operator Reply with quote

Lorenzo Bettini wrote:
Quote:
Hi

I've always used this macro in one of my program

#define foropt for (gengetopt_option_list::iterator it =
gengetopt_options.begin();
it != gengetopt_options.end(), opt = *it;
++it)

Others have explained what is wrong with this code. For another
approach you might want to consider using BOOST_FOREACH which has been
accepted into Boost, but was just too late to be included in 1.33. The
usage would be something like:

BOOST_FOREACH(value_type opt, gengetopt_options )
{ code of loop }

Note that this is SLIGHTLY different, in that it declares a new
variable 'opt'.

See
http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/index.html
for documentation and the files themselves are at
http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler
and then download foreach.zip.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Victor Bazarov
Guest





PostPosted: Wed Aug 17, 2005 2:37 pm    Post subject: Re: question on the comma operator Reply with quote

[email]tony_in_da_uk (AT) yahoo (DOT) co.uk[/email] wrote:
Quote:
for ( ittype it = blah.begin(); it != blah.end(); opt = *it++ )


----------------------

That's not right, as opt is only assigned _after_ the first time
through the loop... - Tony

That's true. It should be made the first statement of the body of
the loop, then.

V

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Lorenzo Bettini
Guest





PostPosted: Wed Aug 17, 2005 2:39 pm    Post subject: Re: question on the comma operator Reply with quote

[email]tony_in_da_uk (AT) yahoo (DOT) co.uk[/email] wrote:
Quote:
Hi Lorenzo,

Yes, the previous code was wrong. The comma operator performs the !=
test and ignores the result, proceeding to evaluate the assignment.
You'll find that doesn't work as a general idiom, as the types in the
comma-separated expression have to be the same, and it's only
coincidence that the pointer you're assigning can be implicitly
converted to int. The && form benefits from short-circuit evaluation,
is safe, and could be used.

For what it's worth, the code would be better expressed as:

for (gengetopt_option_list::iterat=ADor it =
gengetopt_options.begin();
it != gengetopt_options.end(); ++it)
{
gengetopt_option* opt = *it;
// ...
}


I know, but I use this macro in many parts of my program, and I find
this a quicker way

thanks!
Lorenzo

--
+-----------------------------------------------------+
Quote:
Lorenzo Bettini ICQ# lbetto, 16080134 |
PhD in Computer Science |
Dip. Sistemi e Informatica, Univ. di Firenze |
Florence - Italy (GNU/Linux User # 158233) |
Home Page : http://www.lorenzobettini.it |
http://music.dsi.unifi.it XKlaim language |
http://www.lorenzobettini.it/purple Cover Band |
http://www.gnu.org/software/src-highlite |
http://www.gnu.org/software/gengetopt |
http://www.lorenzobettini.it/software/gengen |
http://www.lorenzobettini.it/software/doublecpp |
+-----------------------------------------------------+


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Lorenzo Bettini
Guest





PostPosted: Wed Aug 17, 2005 2:40 pm    Post subject: Re: question on the comma operator Reply with quote

Thomas Richter wrote:
Quote:
General comment:
1) Some people might argue that you should have a good look at
algorithms> and should try for_each() to iterate thru a container
like the above.

I know, but I have to call class methods and I'm not quite confortable
with for_each in this case, especially if you need to pass other
parameters to the method you're calling...

Lorenzo

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Lorenzo Bettini
Guest





PostPosted: Wed Aug 17, 2005 3:15 pm    Post subject: Re: question on the comma operator Reply with quote

Thomas Maeder wrote:
Quote:
I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);


This will give you compiler errors for most types, because they won't
have the necessary implicit conversion. And if they have it, the
results will be surprising because the loop will stop where you don't
expect it to stop.

why?

(opt = *it) assigns the content of it (which is a pointer in turn) to
opt and then checks that it is not null...

Quote:

Why don't you simply write *it and it-> inside the loop?

I use this loop many times, and this way I avoid to write another
instruction...

Lorenzo

--
+-----------------------------------------------------+
Quote:
Lorenzo Bettini ICQ# lbetto, 16080134 |
PhD in Computer Science |
Dip. Sistemi e Informatica, Univ. di Firenze |
Florence - Italy (GNU/Linux User # 158233) |
Home Page : http://www.lorenzobettini.it |
http://music.dsi.unifi.it XKlaim language |
http://www.lorenzobettini.it/purple Cover Band |
http://www.gnu.org/software/src-highlite |
http://www.gnu.org/software/gengetopt |
http://www.lorenzobettini.it/software/gengen |
http://www.lorenzobettini.it/software/doublecpp |
+-----------------------------------------------------+


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Lorenzo Bettini
Guest





PostPosted: Wed Aug 17, 2005 3:16 pm    Post subject: Re: question on the comma operator Reply with quote

Kyle wrote:
Quote:
quote from draft

"A pair of expressions separated by a comma is evaluated left to right
and the value of the left expression is discarded. ... The type and
value of the result are the type and value of the right operand"


expression "it != gengetopt_options.end()" is ignored...


so, probably, up to now, it had always worked because the dereferenced
iterator was NULL...

--
+-----------------------------------------------------+
Quote:
Lorenzo Bettini ICQ# lbetto, 16080134 |
PhD in Computer Science |
Dip. Sistemi e Informatica, Univ. di Firenze |
Florence - Italy (GNU/Linux User # 158233) |
Home Page : http://www.lorenzobettini.it |
http://music.dsi.unifi.it XKlaim language |
http://www.lorenzobettini.it/purple Cover Band |
http://www.gnu.org/software/src-highlite |
http://www.gnu.org/software/gengetopt |
http://www.lorenzobettini.it/software/gengen |
http://www.lorenzobettini.it/software/doublecpp |
+-----------------------------------------------------+


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Thomas Maeder
Guest





PostPosted: Wed Aug 17, 2005 11:15 pm    Post subject: Re: question on the comma operator Reply with quote

Lorenzo Bettini <bettini (AT) dsi (DOT) unifi.it> writes:

Quote:
I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);

This will give you compiler errors for most types, because they won't
have the necessary implicit conversion. And if they have it, the
results will be surprising because the loop will stop where you don't
expect it to stop.

why?

(opt = *it) assigns the content of it (which is a pointer in turn) to
opt and then checks that it is not null...

AFAICT, you didn't tell us that *it evaluates to a pointer.

And even then, I find it awkward to stop the iteration once you hit a
null pointer. Your mileage may vary.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Lorenzo Bettini
Guest





PostPosted: Fri Aug 19, 2005 3:15 pm    Post subject: Re: question on the comma operator Reply with quote

Thomas Maeder wrote:
Quote:
Lorenzo Bettini <bettini (AT) dsi (DOT) unifi.it> writes:


I fixed the problem by using

it != gengetopt_options.end() && (opt = *it);

This will give you compiler errors for most types, because they won't
have the necessary implicit conversion. And if they have it, the
results will be surprising because the loop will stop where you don't
expect it to stop.

why?

(opt = *it) assigns the content of it (which is a pointer in turn) to
opt and then checks that it is not null...


AFAICT, you didn't tell us that *it evaluates to a pointer.

sorry, I forgot about that :-)

Quote:

And even then, I find it awkward to stop the iteration once you hit a
null pointer. Your mileage may vary.

actually, due to the lazy evaluation, the iteration stops when the
iterator reaches the end. Only if it does not reaches the end, it
assigns *it to opt.

The container does not contain null pointers.

Probably I forgot to specify that that loop was not a "general"
iteration: it is a specific case of my program.

Lorenzo

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.