Temporaries

P

Prasoon

Are all temporaries in C++ "rvalues"?

According to me "yes".
Am I right?

However consider the following code.

#include <iostream>


int a;



int& foo()

{

return a;

}



int main()

{

foo()=6;

}


Is there any temporary created in the above code?
According to me "no" there isn't any.

foo() returns just a reference to "a" (and no temporary created).
Correct me if I am wrong.
 
V

Victor Bazarov

Prasoon said:
Are all temporaries in C++ "rvalues"?
No.


According to me "yes".
Am I right?

What do you think?
However consider the following code.

#include <iostream>


int a;



int& foo()

{

return a;

}



int main()

{

foo()=6;

}


Is there any temporary created in the above code?

Not really. I wanted to say "yes, for the '6'", but since 'int' is not
a class, even semantically there is no copy-assignment operator that
*might* require creation of a temporary...
According to me "no" there isn't any.

foo() returns just a reference to "a" (and no temporary created).
Correct me if I am wrong.

You need to do that when the return value of 'foo' is a class which can
be initialised from an int. There will be a temporary created so a
reference can be bound to it when that reference is passed to the
copy-assignment operator.

V
 
V

Victor Bazarov

Victor said:

I may be wrong. Let's see... rvalues are formed by returning from a
function when it's not a reference, by an lvalue-to-rvalue conversion
when an rvalue is expected and lvalue is provided, and by a cast to a
non-reference type. Can temporaries be created in any other context?
If not, then all temporaries are rvalues.

V
 
V

Victor Bazarov

Prasoon said:
Can you give me an example where the temporary created is not an
"rvalue".

When I pass an object to a function by value, is there a temporary? I
wouldn't think so, although I am not sure. The object inside the
function is of "automatic" nature. It's named, so it can't be a
temporary, right? If the argument is initialized by copy-constructing,
then there *might* be a temporary; is it an rvalue? How do we prove it
one way or the other?

V
 
A

Alf P. Steinbach

* Victor Bazarov:
When I pass an object to a function by value, is there a temporary? I
wouldn't think so, although I am not sure. The object inside the
function is of "automatic" nature. It's named, so it can't be a
temporary, right? If the argument is initialized by copy-constructing,
then there *might* be a temporary; is it an rvalue? How do we prove it
one way or the other?

It isn't meaningful to talk of objects as being rvalues or not, and I think that
possibly "rvalue" as being meaningful applied to "object" is an assumption above
-- in which case it may help that I point this out.

There are rvalue /expressions/.

There are no rvalue objects.


Cheers & hth.,

- Alf (huh, dang, what's that fly doing there? ;-) )
 
V

Victor Bazarov

Alf said:
* Victor Bazarov:

It isn't meaningful to talk of objects as being rvalues or not, and I
think that possibly "rvalue" as being meaningful applied to "object" is
an assumption above -- in which case it may help that I point this out.

There are rvalue /expressions/.

There are no rvalue objects.

So, you're saying that the question "are all temporaries rvalues" is not
really valid? An rvalue is a concept, a result of an expression *or*
something an operator (like built-in unary + or -) expects. We can use
temporaries wherever an rvalue is expected, which means the temporary
will be evaluated, converted, whatever, to become the rvalue. And
sometimes when we get an rvalue as the result of some expression, there
is also a temporary close-by...

Slippery, aren't they?

V
 
A

Alf P. Steinbach

* Victor Bazarov:
So, you're saying that the question "are all temporaries rvalues" is not
really valid?

Yes, it's an invalid question, because the concept of rvalue-ness doesn't apply
to temporaries.

On the other hand, most temporaries are produced by rvalue expressions, so there
is a close association.

But on the third hand, many rvalue expressions, e.g. 2+2, do not (necessarily)
produce temporaries.

An rvalue is a concept, a result of an expression *or*
something an operator (like built-in unary + or -) expects. We can use
temporaries wherever an rvalue is expected, which means the temporary
will be evaluated, converted, whatever, to become the rvalue. And
sometimes when we get an rvalue as the result of some expression, there
is also a temporary close-by...
Slippery, aren't they?

Yes, but for other reasons. :)

The standard starts out, in §3.10/1, by saying that "Every expression is either
an lvalue or an rvalue".

It then explains that an lvalue expression /refers/ to an object or function,
and that some rvalue expressions, namely those of class type, can also refer to
objects.

And so it goes on, into details, e.g. that the result of a function call that
does not return a reference, is an rvalue (this particular statement seems a bit
ungood to me, talking about the "result" of the call and implicitly defining
foo(), where foo is a function returning void, as an rvalue expression, i.e. you
can have an rvalue expression that doesn't even denote a value).

A way to understand it is to consider the C origins of the language. In original
C an rvalue (implicitly defined as "not lvalue") was simply a value, as opposed
to an expression referring to something (like dereferencing a pointer). The
introduction of ability to return structures in C (I guess we're then up to K&R
C) possibly made this a little more complicated, I'm not sure what the exact C
rules are for that, but anyway still not very complicated.

In C++, with implicitly defined operators for class types, and where member
routines can be called on rvalue expressions, it gets really complicated. It's a
too narrow concept enforced on the language for conceptual C compatibility.
E.g., as you've seen before, but I think of interest to the OP,

struct S { int x; S( int xVal ): x( xVal ) {} };

S f() { return S( 0 ); }

int main()
{
f() = S(42); // OK, because we have an implicit S::eek:perator=
f().x = 666; // Nope, can't assign to rvalue of basic type.
}

although some compilers will accept the latter assignment.


Cheers,

- Alf
 
F

Francesco

Are all temporaries in C++ "rvalues"?

According to me "yes".
Am I right?

However consider the following code.

#include <iostream>

int a;

int& foo()

{

return a;

}

int main()

{

foo()=6;

}

Is there any temporary created in the above code?
According to me "no" there isn't any.

foo() returns just a reference to "a" (and no temporary created).
Correct me if I am wrong.

I don't know how my code would fit into the discourse that follows to
your post, Praason, anyway, the following...
-------
#include <iostream>

using namespace std;

struct temp {
string id;
void operator=(int i) {
cout << id << ": " << i << endl;
}
};

temp operator+(temp t, string s) {
temp res;
res.id = t.id + s;
return res;
}

int main()
{
temp t;
t.id = "t";
(t + "_temp") = 6;
return 0;
}
-------

....does compile and produces this output:
t_temp: 6

Hence I assume that the expression:
(t + "_temp")
turns into a temporary object which seems an lvalue to me.

But please don't ask me to defend my statement: it's just an
impression, and I could have misunderstood what an lvalue actually is.

Hope that helps,
cheers,
Francesco
 
V

Victor Bazarov

Francesco said:
I don't know how my code would fit into the discourse that follows to
your post, Praason, anyway, the following...
-------
#include <iostream>

using namespace std;

struct temp {
string id;
void operator=(int i) {
cout << id << ": " << i << endl;
}
};

temp operator+(temp t, string s) {
temp res;
res.id = t.id + s;
return res;
}

int main()
{
temp t;
t.id = "t";
(t + "_temp") = 6;
return 0;
}
-------

...does compile and produces this output:
t_temp: 6

Hence I assume that the expression:
(t + "_temp")
turns into a temporary object which seems an lvalue to me.

It's not an lvalue, although its position on the left side of the
assignment expression would suggest that. What we see here is that it's
a modifiable rvalue, and the non-const member function (your operator=
with 'int' as the argument in that case) is called for it. That's
explicitly allowed by the Standard (you can find it in [basic.lval]/10.

The expression in the penultimate statement in 'main' can be rewritten as
(t + "_temp").operator=(6);

which makes it more apparent that a non-const member function is called
to modify the temporary object.
But please don't ask me to defend my statement: it's just an
impression, and I could have misunderstood what an lvalue actually is.

Happens. C++ stretches the meaning of rvalue and lvalue (as Alf
explained elsethread).

V
 
F

Francesco

It's not an lvalue, although its position on the left side of the
assignment expression would suggest that.

I understand that my words (my code) could be interpreted as if I
meant "lvalue == something on the left side of an assignment" but
actually I meant something more, I hope I'll be able to explain myself
in the right way...
What we see here is that it's
a modifiable rvalue, and the non-const member function (your operator=
with 'int' as the argument in that case) is called for it. That's
explicitly allowed by the Standard (you can find it in [basic.lval]/10.

By the way let me say that I wasn't able to read your reference.
I think I could have found it following, for example, the "draft June
2009" link found on this page:
http://www.open-std.org/jtc1/sc22/wg21/docs/projects#14882

Well, unfortunately I cannot get that PDF. I have an odd proxy-only
Internet-connection that chokes on big files, and I assume that's a
big PDF. Sorry if I'm about to lucubrate over a wrong basis... read on
please and correct me where I'll go out-road, if you'll find it worth
doing - and if a more "agile" version of the standard is available
somewhere I'd appreciate a pointer, as I wasn't able to find it by
myself, I'm willing to get the proper sources.
The expression in the penultimate statement in 'main' can be rewritten as
(t + "_temp").operator=(6);

which makes it more apparent that a non-const member function is called
to modify the temporary object.

In this rewriting of yours:
(t + "_temp").operator=(6);
I still see:
(t + "_temp")
as an lvalue, and here is the reason (I've looked up the reference I
had in my mind when posting my code): in section 4.9.6 ("Objects and
lvalue") of TC++PL, 3rd edition, B. Stroustrup writes this line -
please note that the citation is _my_ translation of the Italian text:

"That is, an /object/ is a contiguous region of memory; an /lvalue/ is
an expression with which it is possible to refer to an
object." [emphasis as in the original text]

This definition fits perfectly to my code and as well to your
rewriting, to my eyes, but I understand that the only true reference
should be the standards, which I wasn't able to get.
Happens. C++ stretches the meaning of rvalue and lvalue (as Alf
explained elsethread).

Well, I must admit that my comprehension of the whole thing is really
poor, please excuse me if my posts distract from the topic and don't
add anything to it - in reality my target is just to get a better grip
and to learn something new, stealing as much as I can from you all,
please excuse me for being so selfish ;-)

Cheers,
Francesco
 
F

Francesco

[snip] in section 4.9.6 ("Objects and
lvalue") of TC++PL, 3rd edition, B. Stroustrup writes this line -
please note that the citation is _my_ translation of the Italian text:

"That is, an /object/ is a contiguous region of memory; an /lvalue/ is
an expression with which it is possible to refer to an
object." [emphasis as in the original text]

In addition to what I've reported above, I've found another sentence
in §5.5 ("References") which leads me to turn around the OP question
into its opposite.

Here is the sentence - roughly halfway through the section: "The
initialization of a reference is trivial when the initializer is an
lvalue (an object whose address can be obtained; see §4.9.6)" (once
again, this is my translation of the Italian text).

After reading that, I've run some tests.
First of all I've tried taking the address of a literal number in this
way:
int* ptr_int = &42;

Although it seemed pretty silly to me in first place I've tried it
anyway, and the compiler issued an error telling "non-lvalue in unary
'&'".

Then I've modified the code I posted above in this way:

-------
#include <iostream>

using namespace std;

struct temp {
string id;
void operator=(int i) const {
cout << id << ": " << i << endl;
}
};

temp operator+(temp t, string s) {
temp res;
res.id = t.id + s;
return res;
}

int main()
{
temp t;
t.id = "t";
(t + "_temp") = 1;
temp* ptr_temp = &(t + "_ptr_temp"); // warning here
*ptr_temp = 2;
const temp& ref_temp = t + "_ref_temp";
ref_temp = 3;
t = 4;
return 0;
}
-------

Although it issued a warning about taking the address of a temporary
on the commented line, the code compiled and produced this output:

-------
t_temp: 1
: 2
t_ref_temp: 3
t: 4
-------

Due all the above (citations and tests), can I assume this
reasoning...

- each temporary has an address
- anything having an address is an lvalue
- all temporaries are lvalues

....to be valid?

Waiting for some light on whether I'm following the right path or not,
I'll stop babbling about being a DIY hobbyist - and, of course, I'm
absolutely *not saying* that taking the address of a temporary is a
safe thing to do ;-P

Thank you for your attention,
cheers,
Francesco
 
P

Prasoon

So, you're saying that the question "are all temporaries rvalues" is not
Yes, it's an invalid question, because the concept of rvalue-ness doesn't apply
to temporaries.


The original question was whether all temporaries are rvalues or not?
Why does it seem an invalid question to you?
 
J

James Kanze

Are all temporaries in C++ "rvalues"?

Maybe:). The standard doesn't really define "temporary
object", although it uses the term a lot, in sometimes more or
less contradictary ways. Note that §12.2 starts out by saying
that "Temporaries of class type are created in various contexts:
[...] throwing an exception [...]. Since the value thrown can
bind to a non-const reference, I don't think it is an rvalue.
But most uses tend to more or less equate the two, and most
programmers tend to think of the two as identical.

Strictly speaking, I think a temporary is any object without a
name, where as an rvalue is the result of certain types of
expressions. The definition of rvalue is tied up with
expressions, and the rvalue/lvalue distinction is only defined
for the results of an expression. Most of the time, the two
coincide, at least for objects (references are a different
matter---a reference is always an lvalue, even if it doesn't
have a name, and even if its lifetime corresponds to that of a
temporary).
According to me "yes".
Am I right?

In everyday use, more or less.
However consider the following code.
#include <iostream>
int& foo()
{
return a;
}
int main()
{
foo()=6;
}
Is there any temporary created in the above code?

Yes. The expression 6 is a temporary.
According to me "no" there isn't any.

It depends on your definition of a "temporary".
foo() returns just a reference to "a" (and no temporary
created). Correct me if I am wrong.

Again, it depends on your definition of "temporary". The
reference itself has temporary lifetime, but it is an lvalue.
If you consider such references as "temporaries", then you have
a temporary that is an lvalue. If you don't, then you have an
lvalue, but no temporary. In any case, you don't have a
temporary object (since references aren't objects).

The standard doesn't really say, and there are several ambiguous
cases: temporaries live until the end of the full expression
which creates them (references would be temporaries---but
there's not, as far as I know, anyway to see this lifetime in a
conforming program), but references are always lvalues.
 
J

James Kanze

I may be wrong. Let's see... rvalues are formed by returning
from a function when it's not a reference, by an
lvalue-to-rvalue conversion when an rvalue is expected and
lvalue is provided, and by a cast to a non-reference type.
Can temporaries be created in any other context?

§12.2 mentions "throwing an exception", right at the start. But
then that section goes on to talk about the lifetime of
temporaries, and the object thrown definition doesn't obey those
rules. And what about the temporary created when you initialize
a const reference with an rvalue:

int const& i = 42 ;
// ...

The standard speaks of it as a temporary, e.g. "The second
context [in which temporaries are destroyed at a different point
than the end of a full expression] is when a reference is bound
to a temporary." (First sentence of §12.2/5.) Depending on how
you view it, that "temporary" might be considered the lvalue
with the name "i".
If not, then all temporaries are rvalues.

Define temporary. For that matter, define rvalue. I'm pretty
sure that you can reasonably argue both sides, depending on the
subtilities of the definition use. The standard never gives
even a hint of a definition for "temporary", and the definition
of rvalue is the sentence:
Every expression is either an lvalue or an rvalue
.. So strictly speaking, the two refer to entirely different
concepts, one to "objects" (or "references"---the standard isn't
clear---and what about lambda functions in the upcoming
standard), the other to an annotation of expressions. But
without a more precise definition of "temporary", I wouldn't
like to say.
 
J

James Kanze

* Victor Bazarov:
It isn't meaningful to talk of objects as being rvalues or
not, and I think that possibly "rvalue" as being meaningful
applied to "object" is an assumption above -- in which case
it may help that I point this out.
There are rvalue /expressions/.
There are no rvalue objects.

But "Some rvalue expressions [...] also refer to objects":).

Formally, I tend to agree with you. But where does it say that
a temporary must be an object. Is the return value of "int&
f()" a temporary? If so, you have an lvalue temporary. If not,
what is its lifetime (since if it's not a temporary, it isn't
covered by the lifetime of temporaries)? And can you tell?
 
J

James Kanze

* Victor Bazarov:

[...]
In C++, with implicitly defined operators for class types, and
where member routines can be called on rvalue expressions, it
gets really complicated. It's a too narrow concept enforced on
the language for conceptual C compatibility. E.g., as you've
seen before, but I think of interest to the OP,
struct S { int x; S( int xVal ): x( xVal ) {} };
S f() { return S( 0 ); }
int main()
{
f() = S(42); // OK, because we have an implicit S::eek:perator=
f().x = 666; // Nope, can't assign to rvalue of basic type.
}
although some compilers will accept the latter assignment.

Note that even in C, there are (or were---I haven't checked, but
C99 may have corrected this) some subtle issues. An rvalue
doesn't have an address, so an rvalue array couldn't be
converted to a pointer, and something like:

struct S { int a[ 2 ] ; }

S f() { S result = { 1, 2 } ; return result ; }

int
main()
{
printf( "%d\n", f().a[ 1 ] ) ;
return 0 ;
}

wasn't legal (since the [] operator implies an array to pointer
conversion).
 
J

James Kanze

More completely, it can be rewritten (and is exactly equivalent
to):
operator+( t, "_temp" ).oeprator=( 6 ) ;
In this rewriting of yours:
(t + "_temp").operator=(6);
I still see:
(t + "_temp")
as an lvalue,

The standard says explicitly that it isn't. "A function call is
an lvalue if and only if the result type is a reference."
(§5.2.2/10.)
and here is the reason (I've looked up the reference I had in
my mind when posting my code): in section 4.9.6 ("Objects and
lvalue") of TC++PL, 3rd edition, B. Stroustrup writes this
line - please note that the citation is _my_ translation of
the Italian text:
"That is, an /object/ is a contiguous region of memory; an
/lvalue/ is an expression with which it is possible to refer
to an object." [emphasis as in the original text]

There's no "if and only if" there. An object is a continuous
region of memory, but not all continuous regions of memory are
objects, and an lvalue is an expression with which it is
possible to refer to an object, but it is not necessarily the
only way to refer to an object. (Be wary of the translation, as
well. In the early French translations of Stroustrup, there
were a lot of cases where the translation said something
significantly different, and in a few cases, contradictory, to
the original text. This is, regretfully, a frequent case for
technical translations.)
 
A

Alf P. Steinbach

* Prasoon:
The original question was whether all temporaries are rvalues or not?
Why does it seem an invalid question to you?

It is an invalid question because the rvalue property does not apply to objects.

"rvalue" applies to expressions in the source code.

Corresponding to how an expression may or may not produce an object, a sexual
act may or may not produce a baby. Properties of the sexual act do not transfer
to babies (in general). E.g., most babies are produced by "unsafe" sex, but the
question "are all babies unsafe" is invalid when the word "unsafe" refers to the
property of the sexual act, that the man was not using a condom. One might of
course find a metaphorical meaning for the question, and one might even choose
to interpret it as referring to the baby's conception. But there's no way to
test a baby for that. It's not a property of the baby. And if /we/ choose to
treat the baby differently depending on an imagined "unsafe" property (which we
then create in our minds), then we're doing something we shouldn't. I think.


Cheers & hth.,

- Alf
 
F

Francesco

More completely, it can be rewritten (and is exactly equivalent
to):
    operator+( t, "_temp" ).oeprator=( 6 ) ;


The standard says explicitly that it isn't.  "A function call is
an lvalue if and only if the result type is a reference."
(§5.2.2/10.)

Finally I was able to get my hands on a copy of the standard:
http://www.csci.csusb.edu/dick/c++std/cd2/index.html
I'll have to refer to that until I get access to a more recent copy.

I understand that a function call is not an lvalue, but I never said
so - but once again I understand that my words could have been
interpreted that way. I meant to say that the result of that call is a
temporary, and I consider the _temporary_ to be an lvalue, and I
consider it to be an lvalue just because I can get its address. This
can be arguable and will likely be, and eventually I'll be proved
wrong. No problem.
and here is the reason (I've looked up the reference I had in
my mind when posting my code): in section 4.9.6 ("Objects and
lvalue") of TC++PL, 3rd edition, B. Stroustrup writes this
line - please note that the citation is _my_ translation of
the Italian text:
"That is, an /object/ is a contiguous region of memory; an
/lvalue/ is an expression with which it is possible to refer
to an object." [emphasis as in the original text]

There's no "if and only if" there.  An object is a continuous
region of memory, but not all continuous regions of memory are
objects, and an lvalue is an expression with which it is
possible to refer to an object, but it is not necessarily the
only way to refer to an object.  (Be wary of the translation, as
well.  In the early French translations of Stroustrup, there
were a lot of cases where the translation said something
significantly different, and in a few cases, contradictory, to
the original text.  This is, regretfully, a frequent case for
technical translations.)

I understand that the Italian text could be not perfectly matching to
the original text, but in this very case I think it expresses the
correct meaning - I've found other definitions in English and they
match my translation, as far as I could understand them.

In any case, thank you for your response. I'm still waiting for a
reply somewhere else but that's another story.

Have good time,
Francesco
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top