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 

rvalues, lvalues, Comeau

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





PostPosted: Sun Nov 12, 2006 9:11 am    Post subject: rvalues, lvalues, Comeau Reply with quote



Consider code below, which i have tested with Comeau online compiler:

<code>
struct A {
int tab[5];
};
struct B {
A tab[5];
};

B foo() {
B b;
return b;
}

int main() {
/*
foo() returns a value so 'foo()' is an rvalue, and thus 'foo().tab' is
rvalue as well, so the code shoud be rejected
*/
A (&tab1)[5] = foo().tab; //(1)this code is rejected

/*
below situation is the same and the expression on the right side is also
rvalue
*/
int (&tab2)[5] = foo().tab[0].tab; //(2)this code is however accepted
}
</code>

Now, is it Comeau that gets confused with the second expression, or
perhaps i misunderstood something and 'foo().tab[0].tab' yields lvalue ?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Dag Henriksson
Guest





PostPosted: Wed Nov 15, 2006 6:29 am    Post subject: Re: rvalues, lvalues, Comeau Reply with quote



Kyle skrev:

Quote:
struct A {
int tab[5];
};
struct B {
A tab[5];
};

B foo() {
B b;
return b;
}

int main() {
/*

below situation is the same and the expression on the right side is also
rvalue
*/
int (&tab2)[5] = foo().tab[0].tab; //(2)this code is however accepted
}
/code

Now, is it Comeau that gets confused with the second expression, or
perhaps i misunderstood something and 'foo().tab[0].tab' yields lvalue ?

I think Comeau is right. Note that A[B] yields a lvalue which means
that the whole right side expression should be a lvalue.

--
Dag Henriksson


[ 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: Thu Nov 16, 2006 3:58 am    Post subject: Re: rvalues, lvalues, Comeau Reply with quote



Kyle napisał(a):
Quote:
Consider code below, which i have tested with Comeau online compiler:

code
struct A {
int tab[5];
};
struct B {
A tab[5];
};

B foo() {
B b;
return b;
}

int main() {
/*
foo() returns a value so 'foo()' is an rvalue, and thus 'foo().tab' is
rvalue as well, so the code shoud be rejected
*/
A (&tab1)[5] = foo().tab; //(1)this code is rejected

/*
below situation is the same and the expression on the right side is also
rvalue
*/
int (&tab2)[5] = foo().tab[0].tab; //(2)this code is however accepted
}
/code

Now, is it Comeau that gets confused with the second expression, or
perhaps i misunderstood something and 'foo().tab[0].tab' yields lvalue ?


ermm ... im posting this yet again, as my previous attempts failed (most
probably, due to technical problems mentioned by mods)

--->

I believe i have found relevant fragment:

3.10
3 [Note: some built-in operators and function calls yield lvalues.
[Example: if E is an expression of pointer type, then *E is an lvalue
expression referring to the object or function to which E points. As
another example, the function int& f(); yields an lvalue, so the call
f() is an lvalue expression. ] ]

struct A {
A() { aptr=&a; }
int a;
int* aptr;
};
A foo() { A a; return a; }

int main() {
//int& ref1 = foo().a; //error
int& ref2 = *(foo().aptr) //ok - rhs is lvalue :/
/*
usage of ref2 form now on is undefined behavior, as temporary returned
form 'foo()' no longer exists.
Comeau is correct, compiler cannot reject this code
*/
}

my confusion arose form the fact that its quite obvious (in case of
tables) that rvalue's members should be rvalues as well, however its not
possible to say if a member pointer points to part of rvalue or perhaps
some actual lvalue - given builtin subscript operator is defined in
terms of + and *, whole situation is pretty clear for me now

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Thu Nov 16, 2006 4:12 am    Post subject: Re: rvalues, lvalues, Comeau Reply with quote

James Kanze ha scritto:
Quote:

I think it is the language itself which is confused:-).
'foo().tab[0].tab' is the equivalent of '(*(foo().tab+0)).tab';
the results of the unary * are always an lvalue (by definition),
and the results of the . operator are an lvalue if the left
operand is an lvalue.

The result is, of course, rather ridiculous. Normally, you
can't get the address of an rvalue, in order to apply [] to it,
but the implicit conversion of array to pointer works on
rvalues, and so you do end up with a pointer to an rvalue.

It could be fixed. What about replacing in 5.2.1/1 the sentence

"The expression E1[E2] is identical (by definition) to *((E1)+(E2))"

with

"The expression E1[E2] is identical (by definition) to *((E1)+(E2)),
except that the result is an r-value if either E1 or E2 is an r-value of
array type."

Would it be unreasonable?

Ganesh

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Fri Nov 17, 2006 8:00 am    Post subject: Re: rvalues, lvalues, Comeau Reply with quote

James Kanze ha scritto:
Quote:
Alberto Ganesh Barbati wrote:
James Kanze ha scritto:


It could be fixed. What about replacing in 5.2.1/1 the sentence

"The expression E1[E2] is identical (by definition) to *((E1)+(E2))"

with

"The expression E1[E2] is identical (by definition) to *((E1)+(E2)),
except that the result is an r-value if either E1 or E2 is an r-value of
array type."

Would it be unreasonable?

I think you'd want to make the fix in the definition of the *
operator. What you're suggesting would not stop something like
*foo().tab from being an lvalue. And fixing the wording of the
* operator is a little bit more difficult, since "the result is
an lvalue referring to the object or function to which the
expression points." Maybe something like "the result refers to
the object or function to which the expression points, and is an
lvalue unless the expression is the result of an array to
pointer conversion, in which case, it is an lvalue if and only
if the initial array was an lvalue." Except that in general,
the only way an expression can "refer" to an object or a
function is by being an lvalue. And of course, you also have
the problem that the expression can be more or less arbitrarily
complex, and that the mere presence of an rvalue array in it
doesn't mean that the results cannot be an lvalue. (I think
that the cases would be covered by "pointer arithmetic involving
a pointer resulting from the conversion of an array to pointer",
but there could easily be cases I've missed.)

Very insightful. In fact I deliberately attempted to fix [] instead of *
because I think * can't actually be fixed properly. You already gave one
problematic example, namely "*foo().tab". Let me give another one, which
is, IMHO, even worse:

*(foo().tab + 1)

So it's not enough to check whether the operand of * is an rvalue of
array type. In order to get it right, the compiler should in some way
"remember" the rvalued-ness when computing foo().tab + 1. Poor compiler...

But maybe there is a simple way to overcome this. What if we inhibit the
array-to-pointer conversion for rvalues of array type? That's not too
crazy. In fact you can't write &foo().tab because operator & requires an
lvalue, despite the fact that, if it were legal, the result would be the
same as the array-to-pointer conversion.

(In fact I don't understand why 4.2/1 explicitly include rvalues... I'm
going to post on comp.std.c++ for clarifications).

That, together with a rewording of operator [] similar to one I
proposed, may do the job. Yes, it may break some code. It would be
interesting to see how much and what kind of code it would break and,
most important, if such code is "good" code that we might regret breaking.

Quote:
Don't forget, too, that there are other ways you can
accidentally implicitly convert an rvalue to an lvalue.
Consider something like `ostringstream.flush()'---you start with
a temporary (an rvalue) and end up with an lvalue referring to
it.

I know, but the attitude "I can't fix everything, so let's fix nothing"
is not very productive. Isn't it?

Ganesh

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
James Kanze
Guest





PostPosted: Fri Nov 17, 2006 10:10 am    Post subject: Re: rvalues, lvalues, Comeau Reply with quote

Alberto Ganesh Barbati wrote:
Quote:
James Kanze ha scritto:
Alberto Ganesh Barbati wrote:
James Kanze ha scritto:

It could be fixed. What about replacing in 5.2.1/1 the sentence

"The expression E1[E2] is identical (by definition) to *((E1)+(E2))"

with

"The expression E1[E2] is identical (by definition) to *((E1)+(E2)),
except that the result is an r-value if either E1 or E2 is an r-value of
array type."

Would it be unreasonable?

I think you'd want to make the fix in the definition of the *
operator. What you're suggesting would not stop something like
*foo().tab from being an lvalue. And fixing the wording of the
* operator is a little bit more difficult, since "the result is
an lvalue referring to the object or function to which the
expression points." Maybe something like "the result refers to
the object or function to which the expression points, and is an
lvalue unless the expression is the result of an array to
pointer conversion, in which case, it is an lvalue if and only
if the initial array was an lvalue." Except that in general,
the only way an expression can "refer" to an object or a
function is by being an lvalue. And of course, you also have
the problem that the expression can be more or less arbitrarily
complex, and that the mere presence of an rvalue array in it
doesn't mean that the results cannot be an lvalue. (I think
that the cases would be covered by "pointer arithmetic involving
a pointer resulting from the conversion of an array to pointer",
but there could easily be cases I've missed.)

Very insightful. In fact I deliberately attempted to fix [] instead of *
because I think * can't actually be fixed properly. You already gave one
problematic example, namely "*foo().tab". Let me give another one, which
is, IMHO, even worse:

*(foo().tab + 1)

Same thing, more or less.

A case for which there's obviously no solution (as opposed to no
obvious solution) would be:

template< typename T >
T*
addPtr( T* p, size_t off )
{
return p + off ;
}

*addPtr( foo().tab, 1 ) ;

At some point, the original rvalue-ness is lost.

Quote:
So it's not enough to check whether the operand of * is an rvalue of
array type. In order to get it right, the compiler should in some way
"remember" the rvalued-ness when computing foo().tab + 1. Poor compiler...

I don't think it's that much of a problem. The compiler already
has to track quite a number of attributes of sub-nodes in an
expression. It shouldn't be too difficult for it to propagate a
"points to rvalue" property, as long as we stay in the same
expression tree.

I think rigorously specifying what should be propagated, and
when, is far more work.

Quote:
But maybe there is a simple way to overcome this. What if we inhibit the
array-to-pointer conversion for rvalues of array type? That's not too
crazy. In fact you can't write &foo().tab because operator & requires an
lvalue, despite the fact that, if it were legal, the result would be the
same as the array-to-pointer conversion.

But that would make foo().tab[i] illegal, unless we also defined
[] other than in terms of * and +. Obviously, it was a mistake
to define [] this way to begin with, but I don't think that
there's much we can do about it now.

Quote:
(In fact I don't understand why 4.2/1 explicitly include rvalues... I'm
going to post on comp.std.c++ for clarifications).

Precisely so that you can write things like foo().tab[i].

Quote:
That, together with a rewording of operator [] similar to one I
proposed, may do the job. Yes, it may break some code. It would be
interesting to see how much and what kind of code it would break and,
most important, if such code is "good" code that we might regret breaking.

I'm not sure that we should break bad code, unless there's a
significant payback in return.

The problem here is that we are losing rvalue-ness. It's not
the only place this happens, however, and I suspect that the
other cases are far more frequent in practice. It's part of a
more global problem of lifetime of object management: in C++, it
is easy to get a pointer or a reference to a dead object, or
even to a deleted object. This particular case is, IMHO, a very
minor issue, and there are far more frequent causes of dangling
pointers. (Garbage collection would eliminate one of the most
frequent, but it's not a panacea either.)

Quote:
Don't forget, too, that there are other ways you can
accidentally implicitly convert an rvalue to an lvalue.
Consider something like `ostringstream.flush()'---you start with
a temporary (an rvalue) and end up with an lvalue referring to
it.

I know, but the attitude "I can't fix everything, so let's fix nothing"
is not very productive. Isn't it?

No. But you also have to weigh the effort involved against the
expected gains. What does fixing a problem which only affects a
miniscule proportion of programs buy you? If it's simple to do,
why not, but if it requires reworking significant parts of the
standard, is it worth the effort (and the risk)?

--
James Kanze (GABI Software) email:james.kanze (AT) gmail (DOT) com
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
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.