[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

l-values and r-values

Taras_96

12/8/2008 11:40:00 PM

Hi everyone,

I think I mostly understand l-values and r-values after reading a few
archived posts on this board:

* l-values usually appear on the LHS of an assignment, r-values
usually appear on the RHS of an assignment

An r-value might appear on the LHS of an assignment because of the
following:

* C++ allows a member function to be invoked on a temporary object
* A function returning by value is an r-value
* The assignment operator can be a member function of a UDT

The combination of these factors means that an r-value can appear on
the LHS of an assignment operator:

Foo GetTemp() {return Foo;}

GetTemp() = 5; // which is equivalent to
GetTemp.operator=(5); //

(this of course assumes that the appropriate conversion constructors
and assignment operators are provided for class Foo)

However, I still don't understand how a string literal can be
considered an l-value. The following excerpts hint at an answer:

"String literal: because early C did not have 'const', and so old C
functions that take 'char*' as argument could not be called with
literal strings as actual arguments if string literals were considered
rvalues. However, that may still change. It's just an old
compatibility feature on its way out" - http://tin...

"char *x and char x[] are often used to refer to strings (null
terminated arrays of characters), and they differ in their "lvalue-
ness". " - http://tin...

Wouldn't the following:

void foo(char *);

foo("Hello");

be equivalent to:

char * blah = "Hello";
foo(blah);

? I don't see how this effects the l-valueness of a string literal

Also, is it a defining characteristic of an r-value that you can not
take the address of an r-value (obviously this is true for most cases,
I was wondering if it is, in fact, a defining characteristic, or
whether there are some exceptions)

Taras
30 Answers

Jack Klein

12/9/2008 3:57:00 AM

0

On Mon, 8 Dec 2008 15:40:00 -0800 (PST), Taras_96 <taras.di@gmail.com>
wrote in comp.lang.c++:

> Hi everyone,
>
> I think I mostly understand l-values and r-values after reading a few
> archived posts on this board:
>
> * l-values usually appear on the LHS of an assignment, r-values
> usually appear on the RHS of an assignment

Modifiable lvalues may appear on the LHS of an assignment. Most types
of lvalue can appear on the RHS of an assignment, modifiable or nor.
When this occurs, an lvalue to rvalue conversion is performed.

> An r-value might appear on the LHS of an assignment because of the
> following:
>
> * C++ allows a member function to be invoked on a temporary object
> * A function returning by value is an r-value
> * The assignment operator can be a member function of a UDT
>
> The combination of these factors means that an r-value can appear on
> the LHS of an assignment operator:
>
> Foo GetTemp() {return Foo;}
>
> GetTemp() = 5; // which is equivalent to
> GetTemp.operator=(5); //
>
> (this of course assumes that the appropriate conversion constructors
> and assignment operators are provided for class Foo)
>
> However, I still don't understand how a string literal can be
> considered an l-value. The following excerpts hint at an answer:

Do you understand the actual definition of an lvalue? An lvalue
refers to an object or function. Do you understand the definition of
an object? An object is a region of storage. So a reference to
anything that occupies storage is a valid lvalue.

> "String literal: because early C did not have 'const', and so old C
> functions that take 'char*' as argument could not be called with
> literal strings as actual arguments if string literals were considered
> rvalues. However, that may still change. It's just an old
> compatibility feature on its way out" - http://tin...
>
> "char *x and char x[] are often used to refer to strings (null
> terminated arrays of characters), and they differ in their "lvalue-
> ness". " - http://tin...

This second link is to a very old post, and is quite wrong.

"An lvalue is more a C term than a C++ term. It refers to a value
that can appear on the left (hence "l") side of an assignment."

Wrong, the term lvalue is specifically defined and widely used in the
C++ standard.

"char *x and char x[] are often used to refer to strings (null
terminated arrays of characters), and they differ in their
"lvalue-ness". I point this out because I'm guessing that this
difference may be at the root of your question."

Wrong.

> Wouldn't the following:
>
> void foo(char *);
>
> foo("Hello");

The line above creates an lvalue, an unnamed array of 6 constant
characters. They exist somewhere in memory and have static storage
duration, coming into existence before main() is called, and enduring
until after main() ends execution.

> be equivalent to:
>
> char * blah = "Hello";

The line above creates two lvalues, the first is a pointer to char
'blah', and the second is an unnamed array of 6 constant chars.

> foo(blah);
>
> ? I don't see how this effects the l-valueness of a string literal

It doesn't, the post you quoted, from more than 14 years ago, is
wrong.

> Also, is it a defining characteristic of an r-value that you can not
> take the address of an r-value (obviously this is true for most cases,
> I was wondering if it is, in fact, a defining characteristic, or
> whether there are some exceptions)
>
> Taras

There are some cases where you can take the address of an rvalue, but
there is not much you can actually do with it.

--
Jack Klein
Home: http://JK-Tech...
FAQs for
comp.lang.c http://...
comp.lang.c++ http://www.parashift.com/c++...
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-...

jason.cipriani@gmail.com

12/9/2008 4:21:00 AM

0

On Dec 8, 6:40 pm, Taras_96 <taras...@gmail.com> wrote:
> Hi everyone,
>
> I think I mostly understand l-values and r-values after reading a few
> archived posts on this board:
>
>  * l-values usually appear on the LHS of an assignment, r-values
> usually appear on the RHS of an assignment
>
> An r-value might appear on the LHS of an assignment because of the
> following:
>
>  * C++ allows a member function to be invoked on a temporary object
>  * A function returning by value is an r-value
>  * The assignment operator can be a member function of a UDT
>
> The combination of these factors means that an r-value can appear on
> the LHS of an assignment operator:
>
> Foo GetTemp() {return Foo;}
>
> GetTemp() = 5; // which is equivalent to
> GetTemp.operator=(5); //
>
> (this of course assumes that the appropriate conversion constructors
> and assignment operators are provided for class Foo)
>
> However,  I still don't understand how a string literal can be
> considered an l-value. The following excerpts hint at an answer:
>
> "String literal: because early C did not have 'const', and so old C
> functions that take 'char*' as argument could not be called with
> literal strings as actual arguments if string literals were considered
> rvalues.  However, that may still change.  It's just an old
> compatibility feature on its way out" -http://tin...
>
> "char *x and char x[] are often used to refer to strings (null
> terminated  arrays of characters), and they differ in their "lvalue-
> ness".  " -http://tin...
>


This might be referring to differences between the actual types
"char*" and the type "char[]". For example:

char *x;
x = "Something"; // This is valid (although unsafe, see below).
char y[10];
y = "Something"; // This is not allowed. Note y is on LHS.

That's not to say you can't convert both to a char *:

char *z;
char *x = NULL;
z = x; // This is valid.
char y[10];
z = y; // This is also valid. Note y is on RHS.

And that's the same as this:

void foo (char *z);
char *x = NULL;
foo(x); // This is valid.
char y[10];
foo(y); // This conversion is also valid.


> Wouldn't the following:
>
> void foo(char *);
>
> foo("Hello");
>
> be equivalent to:
>
> char * blah = "Hello";
> foo(blah);


Also note that this is a special case; string literals are able to be
converted to non-const just to main compatibility with old code, but
aren't guaranteed to be in a modifiable part of memory. Therefore:

char *blah = "Hello";
blah[0] = 'J';

Is officially undefined. Whereas:

char array[] = "Hello";
char *blah = array;
blah[0] = 'J';

Is perfectly safe.

In general you should not try to write new code that takes string
literals as non-const char*. Perhaps consider this instead:

void foo (const char *);
const char *blah = "Hello";
foo(blah);

I.e. You should never write a line of code like this:

char *blah = "Hello";


Jason


>
> ? I don't see how this effects the l-valueness of a string literal
>
> Also, is it a defining characteristic of an r-value that you can not
> take the address of an r-value (obviously this is true for most cases,
> I was wondering if it is, in fact, a defining characteristic, or
> whether there are some exceptions)
>
> Taras

James Kanze

12/9/2008 10:18:00 AM

0

On Dec 9, 12:40 am, Taras_96 <taras...@gmail.com> wrote:
> I think I mostly understand l-values and r-values after
> reading a few archived posts on this board:

> * l-values usually appear on the LHS of an assignment, r-values
> usually appear on the RHS of an assignment

Historically, that's where the distinction (and the names) come
from. Today, I'd say that the concept is far more arbitrary;
some operators return rvalues, others lvalues and some require
rvalues, others lvalues. And the only real definition of the
terms is the list of these requirements.

> An r-value might appear on the LHS of an assignment because of
> the following:

> * C++ allows a member function to be invoked on a temporary object
> * A function returning by value is an r-value
> * The assignment operator can be a member function of a UDT

> The combination of these factors means that an r-value can
> appear on the LHS of an assignment operator:

Yes, because a user defined assignment operator isn't an
assignment operator. Once overload resolution has chosen it,
it is a function call, and it obeys the rules of function calls,
not the rules of assignment operators.

> Foo GetTemp() {return Foo;}

> GetTemp() = 5; // which is equivalent to
> GetTemp.operator=(5); //

You mean
GetTemp().operator=( 5 ) ;
for the second line, of course.

> (this of course assumes that the appropriate conversion
> constructors and assignment operators are provided for class
> Foo)

> However, I still don't understand how a string literal can be
> considered an l-value.

It's an array, and all arrays are l-values.

> The following excerpts hint at an answer:

> "String literal: because early C did not have 'const', and so
> old C functions that take 'char*' as argument could not be
> called with literal strings as actual arguments if string
> literals were considered rvalues. However, that may still
> change. It's just an old compatibility feature on its way
> out" -http://tin...

This has nothing to do with lvalue-ness. In C, the type of a
string literal is char[]. In C++, it is char const[], but there
is a special, limited (and I think deprecated) conversion to
char*, to avoid breaking existing code.

> "char *x and char x[] are often used to refer to strings (null
> terminated arrays of characters), and they differ in their
> "lvalue- ness". " -http://tin...

This is just wrong. In both cases, x is an lvalue. They
differ in type, not in lvalue-ness.

> Wouldn't the following:

> void foo(char *);

> foo("Hello");

> be equivalent to:

> char * blah = "Hello";
> foo(blah);

> ? I don't see how this effects the l-valueness of a string
> literal

Yes, and it doesn't.

> Also, is it a defining characteristic of an r-value that you
> can not take the address of an r-value (obviously this is true
> for most cases, I was wondering if it is, in fact, a defining
> characteristic, or whether there are some exceptions)

Well, it's certainly related to the original sense: a lvalue
always designated an object, an rvalue (originally) was just a
value, without an object. In C++, if the rvalue has class type,
then there is an object (and you can obtain its address). Also,
you can initialize a reference to const with an rvalue, and then
take its address. The result is that the distinction
lvalue/rvalue is purely arbitrary.

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

Taras_96

12/9/2008 10:20:00 PM

0

On Dec 9, 3:56 am, Jack Klein <jackkl...@spamcop.net> wrote:
> On Mon, 8 Dec 2008 15:40:00 -0800 (PST), Taras_96 <taras...@gmail.com>
> wrote in comp.lang.c++:
>
>
> > However,  I still don't understand how a string literal can be
> > considered an l-value. The following excerpts hint at an answer:
>
> Do you understand the actual definition of an lvalue?  An lvalue
> refers to an object or function.  Do you understand the definition of
> an object?  An object is a region of storage.  So a reference to
> anything that occupies storage is a valid lvalue.
>

Stroustrup states that: "there is a need for a name for "something in
memory." This is the simplest and most fundamental notion of an
object. That is, an /object/ is a contiguous region of storage; an /
lvalue/ is an expression that refers to an object"

But in a sense, the '5' in the expression:

int i = 5;

would be stored somewhere in memory (ultimately, unless it is
optimised out). I suppose that '5' can not be an l-value, because it
isn't an expression that refers to an object (it actually is the
object itself).

Additionally, K&R states that: "An object is a manipulatable region of
storage; an lvalue is an expression referring to an object"

I suppose with that in mind you can't really modify the value of 5, so
with this definition '5' isn't an object.

I'm thinking of an r-value more like a 'concept' rather than a an
object, if that makes any sense. You can not change the 'concept' of
the number 5, 5 will always be 5. This is re-inforced in C++ by only
allowing to take a constant reference to temporaries:

const int & rr = 3;

Otherwise, you could do something like this:

rr = 4;

which would then change 3 to be equal to 4, which doesn't make sense!

Taras_96

12/9/2008 10:21:00 PM

0

On Dec 9, 10:18 am, James Kanze <james.ka...@gmail.com> wrote:
> On Dec 9, 12:40 am, Taras_96 <taras...@gmail.com> wrote:
>
> > I think I mostly understand l-values and r-values after
> > reading a few archived posts on this board:
> >  * l-values usually appear on the LHS of an assignment, r-values
> > usually appear on the RHS of an assignment
>
> Historically, that's where the distinction (and the names) come
> from.  Today, I'd say that the concept is far more arbitrary;
> some operators return rvalues, others lvalues and some require
> rvalues, others lvalues.  And the only real definition of the
> terms is the list of these requirements.

That's why I stated 'usually' :)

Taras_96

12/9/2008 10:30:00 PM

0

Your posts made me dig deeper into TCPL, and there it was in 5.2.2:

"The type of a string literal is ‘‘array of the appropriate number of
c o n s t characters,’’ so " B o h r " is
of type c o n s t c h a r []"

So thus a string literal is an l-value.

Your responses say that a string literal is static and in a non-
modifiable area of memory. Also, Bjarne writes "A string literal is
statically allocated so that it is safe to return one from a function"

Is this in any way similar to the Java implementation of Strings,
where a string is immutable and contained within a string pool (I
realise that this is a c++ group, so apologies), in that in C++ the
same string may refer to the same memory location (this is
implementation defined) - assigning two literal strings that are the
same to different pointers is conceptually similar to assigning the
integer 5 to two different variables? Was there any reason apart from
efficiency than choosing this meaning rather than 'each string literal
creates a separate object'?

Taras

Victor Bazarov

12/9/2008 10:55:00 PM

0

Taras_96 wrote:
> Your posts made me dig deeper into TCPL, and there it was in 5.2.2:
>
> "The type of a string literal is ??array of the appropriate number of
> c o n s t characters,?? so " B o h r " is
> of type c o n s t c h a r []"
>
> So thus a string literal is an l-value.

Non-modifiable, IIUIC.

>
> Your responses say that a string literal is static and in a non-
> modifiable area of memory. Also, Bjarne writes "A string literal is
> statically allocated so that it is safe to return one from a function"
>
> Is this in any way similar to the Java implementation of Strings,
> where a string is immutable and contained within a string pool (I
> realise that this is a c++ group, so apologies), in that in C++ the
> same string may refer to the same memory location (this is
> implementation defined) - assigning two literal strings that are the
> same to different pointers is conceptually similar to assigning the
> integer 5 to two different variables? Was there any reason apart from
> efficiency than choosing this meaning rather than 'each string literal
> creates a separate object'?

It is implementation-defined whether it makes the same string literals
shared (in fact, Visual C++ can do that, IIRC). With some compilers
(actually, linkers), this assertion

assert("abc" == "abc");

will be satisfied. But there is no requirement either way. If that's
what you're asking.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Andrey Tarasevich

12/9/2008 10:57:00 PM

0

Taras_96 wrote:
> ...
> I think I mostly understand l-values and r-values after reading a few
> archived posts on this board:
>
> * l-values usually appear on the LHS of an assignment, r-values
> usually appear on the RHS of an assignment

Firstly, the above applies specifically to _built-in_ assignment
operator, not to every assignment in the program. Once we start talking
about user-defined assignment operators, all bets are off. There's no
relationship between lvalues/rvalues and user-defined assignment operators.

Secondly, once we restrict the consideration to built-in assignment
operator, the word "usually" becomes important. It is true that the
built-in assignment requires a [modifiable] lvalue on its LHS, this is
in no way a defining property of lvalue.

As for the RHS, it doesn't make much sense to say that an rvalue usually
appears there. Normally, just about anything can appear on the RHS. It
is correct to say that the RHS of an assignment is _used_ _as_ an
rvalue, but not correct o say that it _is_ an rvalue.

> An r-value might appear on the LHS of an assignment because of the
> following:
>
> * C++ allows a member function to be invoked on a temporary object
> * A function returning by value is an r-value
> * The assignment operator can be a member function of a UDT

You seem to be talking about the overladed assignment here. Once again,
the overloaded assignment has virtually no connection to the distinction
between lvalues and rvalues. It doesn't make much sense to get it
involved at all.

> However, I still don't understand how a string literal can be
> considered an l-value. The following excerpts hint at an answer:
>
> "String literal: because early C did not have 'const', and so old C
> functions that take 'char*' as argument could not be called with
> literal strings as actual arguments if string literals were considered
> rvalues. However, that may still change. It's just an old
> compatibility feature on its way out" - http://tin...
>
> "char *x and char x[] are often used to refer to strings (null
> terminated arrays of characters), and they differ in their "lvalue-
> ness". " - http://tin...

You seem to be using a bad source for your information. In both C and
C++ the term 'lvalue' is not tied to the "LHS of an assignment" in any
way. It is true that this is how this term was born, but in the end its
meaning was modified to something completely different. In a simplified
form, an lvalue is something that has a location in storage (address in
memory). In C the term 'lvalue' is synonymous with the term 'object'. In
C++ it is defined to also include functions and has some other
intricacies, but the general idea of "location in memory" remains the same.

If you want to express it through operators, an lvalue in C++ is
something you can apply the built-in unary operator '&' to (note: not
the LHS of the assignment operator, but the operand of address-of
operator). This is in no way an exact criterion, but it conveys the
general idea rather well.

> Wouldn't the following:
>
> void foo(char *);
>
> foo("Hello");
>
> be equivalent to:
>
> char * blah = "Hello";
> foo(blah);
>
> ? I don't see how this effects the l-valueness of a string literal

It doesn't. Pointers always point to lvalues in C and C++. The source
you are using doesn't make any sense.

> Also, is it a defining characteristic of an r-value that you can not
> take the address of an r-value (obviously this is true for most cases,
> I was wondering if it is, in fact, a defining characteristic, or
> whether there are some exceptions)

It works one way only: you can't take the address (i.e. use the built-in
unary '&') on an rvalue. However, just because you can't use the
built-in '&' on something doesn't mean it is an rvalue.

--
Best regards,
Andrey Tarasevich

Pete Becker

12/9/2008 11:19:00 PM

0

On 2008-12-09 17:19:46 -0500, Taras_96 <taras.di@gmail.com> said:

>
> I'm thinking of an r-value more like a 'concept' rather than a an
> object, if that makes any sense. You can not change the 'concept' of
> the number 5, 5 will always be 5. This is re-inforced in C++ by only
> allowing to take a constant reference to temporaries:
>
> const int & rr = 3;

Err, the issue here is that you can't initialize a reference to a
modifiable int with a constant.

>
> Otherwise, you could do something like this:
>
> rr = 4;
>
> which would then change 3 to be equal to 4, which doesn't make sense!

Maybe not, but in Fortran you could do it. Accidentally, of course.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

ram

12/9/2008 11:40:00 PM

0

Taras_96 <taras.di@gmail.com> writes:
>But in a sense, the '5' in the expression:
>int i = 5;

This line is not an expression, but a declaration.

>would be stored somewhere in memory

»5« is an integer literal. What is being stored is its value.
For example, the literal »5« and »05« have the same value.

>I suppose that '5' can not be an l-value, because it isn't an
>expression that refers to an object (it actually is the object
>itself).

»5« is not an object at all. »5« is an integer literal.

>I suppose with that in mind you can't really modify the value
>of 5, so with this definition '5' isn't an object.

The value of literals is given by the C++ specification or
sometimes by the C++ implementation, it can not be modified
by a program.

>I'm thinking of an r-value more like a 'concept' rather than a
>an object, if that makes any sense.

Yes, it makes some sense. But thinking of an r-value as
an object in the first place is so wrong that there actually
is no need to deny it. (»I am thinking of a car more like a
vehicle than a building.«)

>You can not change the 'concept' of the number 5, 5 will always be 5.

Yes.

(Beyond C++:
5 is not a physical system (like an object) that can change in
time. It is a mathematical value that is not related to time.)