Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > lvalue rvalue

Reply
Thread Tools

lvalue rvalue

 
 
Denis Remezov
Guest
Posts: n/a
 
      07-16-2004
JKop wrote:
>
> The following compiles:
>
> // syrup.cpp
>
> struct DoubleInDisguise
> {
> double data;
> };
>
> double Chocolate1()
> {
> double blah = 67.22;
>
> return blah;
> }
>
> DoubleInDisguise Chocolate2()
> {
> DoubleInDisguise blah = { 67.22 };
>
> return blah;
> }
>
> /*
> inline void Manipulate(double& input)
> {
> input = 222.76;
> }
> */
>
> inline void Manipulate(DoubleInDisguise& input)
> {
> //input.data = 222.76;
> }
>
> int main()
> {
> //Manipulate( Chocolate1() );
>
> Chocolate2() = DoubleInDisguise();
>
> // Manipulate( Chocolate2() );
> }
>
> See how the return-value from Chocolate2() can have an assigment done to it.
> This suggests that its non-const first of all, and secondly that it's an
> lvalue.


[...]

No, it is an rvalue. Yes, for built-in types, you can only assign to an
lvalue. But since DoubleInDisguise is a user-defined type, it has a member
function operator = (semantically, anyway), which can be called on an rvalue.

To prevent this kind of confusion, you can change Chocolate2 to
DoubleInDisguise const Chocolate2() {...}

Denis
 
Reply With Quote
 
 
 
 
JKop
Guest
Posts: n/a
 
      07-16-2004
The following compiles:


// syrup.cpp

struct DoubleInDisguise
{
double data;
};

double Chocolate1()
{
double blah = 67.22;

return blah;
}

DoubleInDisguise Chocolate2()
{
DoubleInDisguise blah = { 67.22 };

return blah;
}


/*
inline void Manipulate(double& input)
{
input = 222.76;
}
*/

inline void Manipulate(DoubleInDisguise& input)
{
//input.data = 222.76;
}

int main()
{
//Manipulate( Chocolate1() );

Chocolate2() = DoubleInDisguise();

// Manipulate( Chocolate2() );
}


See how the return-value from Chocolate2() can have an assigment done to it.
This suggests that its non-const first of all, and secondly that it's an
lvalue. But now, see my last line of code, take away the // commenters. It
won't compile. You can assign to a temporary, yet it can't act as a
double&?! What the hell is going on?

-JKop
 
Reply With Quote
 
 
 
 
Ioannis Vranos
Guest
Posts: n/a
 
      07-16-2004
JKop wrote:
> The following compiles:
>
>
> // syrup.cpp
>
> struct DoubleInDisguise
> {
> double data;
> };
>
> double Chocolate1()
> {
> double blah = 67.22;
>
> return blah;
> }
>
> DoubleInDisguise Chocolate2()
> {
> DoubleInDisguise blah = { 67.22 };
>
> return blah;
> }
>
>
> /*
> inline void Manipulate(double& input)
> {
> input = 222.76;
> }
> */
>
> inline void Manipulate(DoubleInDisguise& input)
> {
> //input.data = 222.76;
> }
>
> int main()
> {
> //Manipulate( Chocolate1() );
>
> Chocolate2() = DoubleInDisguise();



The above line does this: Chocolate2() returns a temporary
DoubleInDisguise object which is then assigned the value of the
temporary on the right (which is initialised to 0).


>
> // Manipulate( Chocolate2() );




The above takes a double as an argument while you are passing it a
DoubleInDisguise.






Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
 
Reply With Quote
 
Ioannis Vranos
Guest
Posts: n/a
 
      07-16-2004
Ioannis Vranos wrote:

> JKop wrote:
>
>> The following compiles:
>>
>>
>> // syrup.cpp
>>
>> struct DoubleInDisguise
>> {
>> double data;
>> };
>>
>> double Chocolate1()
>> {
>> double blah = 67.22;
>>
>> return blah;
>> }
>>
>> DoubleInDisguise Chocolate2()
>> {
>> DoubleInDisguise blah = { 67.22 };
>>
>> return blah;
>> }
>>
>>
>> /*
>> inline void Manipulate(double& input)
>> {
>> input = 222.76;
>> }
>> */
>>
>> inline void Manipulate(DoubleInDisguise& input)
>> {
>> //input.data = 222.76;
>> }
>>
>> int main()
>> {
>> //Manipulate( Chocolate1() );
>>
>> Chocolate2() = DoubleInDisguise();

>
>
>
> The above line does this: Chocolate2() returns a temporary
> DoubleInDisguise object which is then assigned the value of the
> temporary on the right (which is initialised to 0).
>
>
>>
>> // Manipulate( Chocolate2() );




The above is passing to the void Manipulate(DoubleInDisguise&) a
temporary of type DoubleInDisguise which is not allowed since it is
getting a reference. The only way you can do it is by making the function

inline void Manipulate(const DoubleInDisguise& input)
{
//input.data = 222.76;
}


that is with a const reference. I suggest you get and read TC++PL 3, you
will find much knowledge in this book.






Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
 
Reply With Quote
 
DaKoadMunky
Guest
Posts: n/a
 
      07-16-2004
struct Foo
{
void DoSomething() {}
};

void DoSomethingWithFoo(Foo& foo)
{
foo.DoSomething();
}

int main()
{
//So in this context the temporary is non-const...
Foo().DoSomething();

//...but in this context the temporary is const?
DoSomethingWithFoo(Foo());

//Note that I can bind a reference to the original
//temporary by doing the following. Is this
//undefined behavior?
DoSomethingWithFoo(Foo().operator=(Foo()));

return 0;
}

Oh well.

Maybe grokking this is beyond me. Time to move on.
 
Reply With Quote
 
Ioannis Vranos
Guest
Posts: n/a
 
      07-16-2004
DaKoadMunky wrote:

> struct Foo
> {
> void DoSomething() {}
> };
>
> void DoSomethingWithFoo(Foo& foo)

[7]> {
> foo.DoSomething();
> }
>
> int main()
> {
> //So in this context the temporary is non-const...
> Foo().DoSomething();
>
> //...but in this context the temporary is const?

[17]> DoSomethingWithFoo(Foo());
>
> //Note that I can bind a reference to the original
> //temporary by doing the following. Is this
> //undefined behavior?
> DoSomethingWithFoo(Foo().operator=(Foo()));
>
> return 0;
> }
>
> Oh well.
>
> Maybe grokking this is beyond me. Time to move on.




> Executing: C:\Program Files\ConTEXT\ConExec.exe

"c:\mingw\bin\g++.exe" -std=c++98 -pedantic-errors -Wall
-fexpensive-optimizations -O3 -ffloat-store -mcpu=pentiumpro "temp.cpp"
-o temp

temp.cpp: In function `int main()':
temp.cpp:17: error: could not convert `Foo()' to `Foo&'
temp.cpp:7: error: in passing argument 1 of `void DoSomethingWithFoo(Foo&)'
> Execution finished.







Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
 
Reply With Quote
 
DaKoadMunky
Guest
Posts: n/a
 
      07-16-2004
Using MSVC++.NET I also received an error, as expected, on line 17.

I did not get an error on line 7.

The online compiler at http://www.comeaucomputing.com/pcgi-bin/compiler.cgi set
for Windows XP generated the same results...error on line 17 and no error on
line 7.

Of course using compilers is the wrong way to determine what is legal and
illegal


 
Reply With Quote
 
Andrey Tarasevich
Guest
Posts: n/a
 
      07-16-2004
JKop wrote:
> ...
> int main()
> {
> //Manipulate( Chocolate1() );
>
> Chocolate2() = DoubleInDisguise();
>
> // Manipulate( Chocolate2() );
> }
>
>
> See how the return-value from Chocolate2() can have an assigment done to it.
> This suggests that its non-const first of all, and secondly that it's an
> lvalue.


No, it doesn't suggest that it's an lvalue. Only built-in assignment
operator requires an lvalue on it left-hand side. User-defined
assignment operators don't have this requirement.

> But now, see my last line of code, take away the // commenters. It
> won't compile. You can assign to a temporary, yet it can't act as a
> double&?! What the hell is going on?


Non-constant references _cannot_ be bound to rvalues. Non-constant
methods _can_ be called on non-constant rvalue objects. There's certain
intuitive feeling of asymmetry here, but that's just the way it is in C++.

--
Best regards,
Andrey Tarasevich

 
Reply With Quote
 
Ioannis Vranos
Guest
Posts: n/a
 
      07-16-2004
DaKoadMunky wrote:
> Using MSVC++.NET I also received an error, as expected, on line 17.
>
> I did not get an error on line 7.
>
> The online compiler at http://www.comeaucomputing.com/pcgi-bin/compiler.cgi set
> for Windows XP generated the same results...error on line 17 and no error on
> line 7.



Yes the first error was indicated in line 17 and then it mentions line 7
where there is the function declaration/definition itself.


> Of course using compilers is the wrong way to determine what is legal and
> illegal



Yes I did not use the compiler in my original post, but when I saw your
post with the "it works" attitude, I decided to use it in your code.


Temporaries are destroyed just after you pass them to a function,
including when the function is taking references, with the exception
when it takes const references as arguments. In the last case, the
temporary persists until it reaches the end of the function and this is
the way many standard library algorithms work.






Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
 
Reply With Quote
 
Ali Cehreli
Guest
Posts: n/a
 
      07-16-2004
On Fri, 16 Jul 2004 16:23:17 -0700, Ioannis Vranos wrote:

> Temporaries are destroyed just after you pass them to a function,


They are destroyed at the end of the complete statement where they are
created. The complete statement may have many other function
calls. The destruction of the temporary must wait untill all of those
calls are completed.

> including when the function is taking references, with the exception
> when it takes const references as arguments.


We cannot pass temporaries to functions taking non-const references
anyway. So I will limit the rest of the discussion to functions that
take const references.

> In the last case, the
> temporary persists until it reaches the end of the function and this is
> the way many standard library algorithms work.


This is incorrect. The temporary lives longer than the function call
as I described above. The destruction must wait until the statement
completes.

Here is a code that tries to demonstrates this:

class C
{
int i_;

public:
C(int i) : i_(i) { cout << "construct\n"; }
C(C const &) { cout << "copy\n"; }
C & operator=(C const &) { cout << "assign\n"; }
~C() { cout << "destroy\n"; }

void use() const {}
};

int foo(C const & c)
{
c.use();
cout << "foo\n";
return 0;
}

void bar(int, C const &)
{
cout << "bar\n";
}

C blah()
{
return 1;
}

int main()
{
bar(foo(blah()), C(0));
}

The two temporaries created must live until bar exits. The output of
the program must have two 'destroy's printed *after* 'bar'.

Ali
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Giving an rvalue ref to a function taking an rvalue ref Juha Nieminen C++ 13 08-29-2012 09:25 PM
operators requiring lvalue/rvalue operands and resulting in rvalue/lvalue Kavya C Programming 9 10-28-2006 01:45 AM
const and non-const operator[] Vs. lvalue and rvalue use Mark Stijnman C++ 2 04-22-2005 02:32 PM
rvalue / lvalue operator[] Gonzalo Aguirre C++ 4 01-02-2004 06:02 PM
++x returns lvalue but x++ return rvalue Chris Mantoulidis C++ 4 12-29-2003 07:00 AM



Advertisments