Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > non-const reference to temporary object

Reply
Thread Tools

non-const reference to temporary object

 
 
rajath575@gmail.com
Guest
Posts: n/a
 
      11-27-2008
I encountered a problem when passing temporary variable as a non const
variable. The message was " initial value of reference to non-const
must be an lvalue "

void foo(MyClass &Var)
{
// Whatever
}

foo(MyClass());

What is the exact problem here?
Does it have to do anything with the scope of the temporary MyClass
passed to the function? What is its scope?
And how does changing the declaration of foo as void foo(const MyClass
&Var) change anything?
 
Reply With Quote
 
 
 
 
Rolf Magnus
Guest
Posts: n/a
 
      11-27-2008
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

> I encountered a problem when passing temporary variable as a non const
> variable.


Not exactly. It's not about passing it to a function, but about binding it
to a reference.

> The message was " initial value of reference to non-const
> must be an lvalue "
>
> void foo(MyClass &Var)
> {
> // Whatever
> }
>
> foo(MyClass());
>
> What is the exact problem here?


C++ doesn't allow binding a temporary to a non-const reference.

 
Reply With Quote
 
 
 
 
Salt_Peter
Guest
Posts: n/a
 
      11-27-2008
On Nov 26, 11:00 pm, (E-Mail Removed) wrote:
> I encountered a problem when passing temporary variable as a non const
> variable. The message was " initial value of reference to non-const
> must be an lvalue "
>
> void foo(MyClass &Var)
> {
> // Whatever
>
> }
>
> foo(MyClass());
>
> What is the exact problem here?
> Does it have to do anything with the scope of the temporary MyClass
> passed to the function? What is its scope?


Scope is not the same as lifetime, scope refers to an object's
visibility.
A temporary's lifetime is ephemeral unless it is kept alive somehow.

> And how does changing the declaration of foo as void foo(const MyClass
> &Var) change anything?


It changes everything.
Myclass() generates a temporary with a lifetime limited to its short
existance.

Myclass& r = MyClass(); // temporary is born and dies here
// accesing r is now undefined behavior

a const reference extends the lifetime of the temporary

const Myclass& r_ = MyClass(); // temp is born and is kept alive
// r_ is still valid here
// the temporary stays valid until r_'s lifetime ends

your example above does exactly the same thing:

....
void foo(const MyClass& r_val)
{
// r_val is still valid here
}
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      11-27-2008
Salt_Peter wrote:

> On Nov 26, 11:00 pm, (E-Mail Removed) wrote:
>> I encountered a problem when passing temporary variable as a non const
>> variable. The message was " initial value of reference to non-const
>> must be an lvalue "
>>
>> void foo(MyClass &Var)
>> {
>> // Whatever
>>
>> }
>>
>> foo(MyClass());
>>
>> What is the exact problem here?
>> Does it have to do anything with the scope of the temporary MyClass
>> passed to the function? What is its scope?

>
> Scope is not the same as lifetime, scope refers to an object's
> visibility.


True.

> A temporary's lifetime is ephemeral unless it is kept alive somehow.


In the case from above, that is immaterial. The temporary lives until the
end of the full expression, which would be long enough for the call to
foo() to complete. One can see this by cheating a little:

#include <iostream>
#include <ostream>

struct MyClass {

MyClass ( void ) {
std::cout << "constructed\n";
}

~MyClass ( void ) {
std::cout << "destroyed\n";
}

MyClass & me ( void ) {
return ( *this );
}

};

void foo ( MyClass & obj ) {
std::cout << "call to foo\n";
}

int main ( void ) {
foo ( MyClass().me() ), std::cout << "even later than foo\n";
}

This prints:

constructed
call to foo
even later than foo
destroyed


[snip]

To the OP:

The reason lies in the standard [8.5.3/5], which explicitly prevents
initializing a non-const reference from a temporary. Nonetheless, calling
non-const member functions on temporaries is fine (see the me() function
above). Thus:

std::vector<int> iv;
std::vector<int>().swap( iv ); // ok
iv.swap( std::vector<int>() ); // not ok


The following trick is not standard conforming, but I think it will be with
C++0X:

template < typename T >
T & lvalue_cast ( T const & ref ) {
return( const_cast< T & >( ref ) );
}

With that, you could do:

foo( lvalue_cast( MyClass() ) );



Best

Kai-Uwe Bux
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      11-27-2008
On Nov 27, 6:18 am, Salt_Peter <(E-Mail Removed)> wrote:
> On Nov 26, 11:00 pm, (E-Mail Removed) wrote:


> > I encountered a problem when passing temporary variable as a
> > non const variable. The message was " initial value of
> > reference to non-const must be an lvalue "


> > void foo(MyClass &Var)
> > {
> > // Whatever
> > }


> > foo(MyClass());


> > What is the exact problem here?
> > Does it have to do anything with the scope of the temporary
> > MyClass passed to the function? What is its scope?


> Scope is not the same as lifetime, scope refers to an object's
> visibility.


To a symbols visibility. Scope doesn't concern objects, but
symbols (and it's purely a lexical concept, not runtime---except
when language rules associate lifetime with scope).

> A temporary's lifetime is ephemeral unless it is kept alive
> somehow.


A temporary's lifetime is until the end of the full expression,
normally.

> > And how does changing the declaration of foo as void
> > foo(const MyClass &Var) change anything?


> It changes everything. Myclass() generates a temporary with a
> lifetime limited to its short existance.


> Myclass& r = MyClass(); // temporary is born and dies here
> // accesing r is now undefined behavior


> a const reference extends the lifetime of the temporary


I think you're missing the point. First, the language rules
don't allow initializing a reference with an rvalue unless it is
a reference to a non-volatile const type. That's what's causing
his error. (There is one exception: if the rvalue is a class
type with a user defined conversion to an lvalue type, it is
treated as an lvalue, and the conversion is used.) Lifetime
simply isn't a consideration here. The second point (not
relavent to his example) is that if a reference is initialized
with a temporary, the lifetime of that temporary is extended to
match the lifetime of the reference. This really has nothing to
do with const, except that the situation can't be reached unless
the reference is to a non-volatile const. (This is, IMHO, a
fairly tricky point, and irrelevant to most code anyway.)

> const Myclass& r_ = MyClass(); // temp is born and is kept alive
> // r_ is still valid here
> // the temporary stays valid until r_'s lifetime ends


> your example above does exactly the same thing:


No it doesn't. In his case, the lifetime of the temporary is
until the end of the full expression. Longer than the lifetime
of the temporary it initializes. And none of the special rules
ever reduces the lifetime of a temporary.

--
James Kanze (GABI Software) email:(E-Mail Removed)
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
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      11-27-2008
On Nov 27, 6:39 am, Kai-Uwe Bux <(E-Mail Removed)> wrote:
> Salt_Peter wrote:
> > On Nov 26, 11:00 pm, (E-Mail Removed) wrote:
> >> I encountered a problem when passing temporary variable as
> >> a non const variable. The message was " initial value of
> >> reference to non-const must be an lvalue "


> >> void foo(MyClass &Var)
> >> {
> >> // Whatever
> >> }


> >> foo(MyClass());


> >> What is the exact problem here?
> >> Does it have to do anything with the scope of the temporary
> >> MyClass passed to the function? What is its scope?


> > Scope is not the same as lifetime, scope refers to an
> > object's visibility.


> True.


False. In some ways, it seems like a nit, but we are talking
about vocabulary, and it's an important distinction. Scope does
not have anything to do with objects; it is a property of a
symbol. Talking about the scope of an unnamed temporary has no
meaning. And objects can be visible through several different
symbols (that's what references are for), each with different
scope.

[...]
> The following trick is not standard conforming, but I think it
> will be with C++0X:


> template < typename T >
> T & lvalue_cast ( T const & ref ) {
> return( const_cast< T & >( ref ) );
> }


> With that, you could do:


> foo( lvalue_cast( MyClass() ) );


Why isn't it conforming?

The real question is why he wants to bind the temporary to a
non-const reference. There are several legitimate uses, but
each has a somewhat different effective work-around.

--
James Kanze (GABI Software) email:(E-Mail Removed)
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
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      11-27-2008
James Kanze wrote:
> First, the language rules
> don't allow initializing a reference with an rvalue unless it is
> a reference to a non-volatile const type. That's what's causing
> his error. (There is one exception: if the rvalue is a class
> type with a user defined conversion to an lvalue type, it is
> treated as an lvalue, and the conversion is used.)


Just to elaborate on the parenthetical remark, the type of the lvalue must
be different from the type of the rvalue, i.e., the following should not
compile:

struct X {

int x;

X ( int i = 0 )
: x ( i )
{}

operator X & ( void ) const {
return ( *this );
}

};

void add_one ( X & ref ) {
++ ref.x;
}

#include <iostream>

int main ( void ) {
X const a ( 2 );
add_one( a );
std::cout << a.x << '\n';
}

The reason is that as per [12.3.2/1], the conversion cannot be called to
convert an rvalue of type T to an lvalue of type T&.


Best

Kai-Uwe Bux
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      11-27-2008
James Kanze wrote:

...]
>> The following trick is not standard conforming, but I think it
>> will be with C++0X:

>
>> template < typename T >
>> T & lvalue_cast ( T const & ref ) {
>> return( const_cast< T & >( ref ) );
>> }

>
>> With that, you could do:

>
>> foo( lvalue_cast( MyClass() ) );

>
> Why isn't it conforming?


Well, there are two issues with this code.

(a) The standard allows copying (in a non-slicing manner) of the object
while initializing the const reference. Therefore, the lvalue_cast<> might
not yield a reference to the temporary created by MyClass() but to another
temporary constructed therefrom by copy-construction.

(b) Related but slightly different, the above assumes the existence of a
copy constructor where none should be needed.

For most code those points do not matter, of course. I would agree that
non-conforming is probably not exact. However, the function name creates
the impression that you would get a reference to the object passed in; and
that is not guaranteed (but I think it will be).


> The real question is why he wants to bind the temporary to a
> non-const reference. There are several legitimate uses, but
> each has a somewhat different effective work-around.


In my opinion, we should not need the work arounds.



Best

Kai-Uwe Bux
 
Reply With Quote
 
rajath575@gmail.com
Guest
Posts: n/a
 
      11-27-2008

> The real question is why he wants to bind the temporary to a
> non-const reference. *There are several legitimate uses, but
> each has a somewhat different effective work-around.


I was using a Symbian C++ macro to generate a descriptor
( temporary ) and was trying to write it to a file using a function
which took a non-const parameter. Probably not the right place to
discuss.
Thanks to everyone who answered.


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      11-27-2008
On Nov 27, 10:22 am, Kai-Uwe Bux <(E-Mail Removed)> wrote:
> James Kanze wrote:
> [..]
> >> The following trick is not standard conforming, but I think it
> >> will be with C++0X:


> >> template < typename T >
> >> T & lvalue_cast ( T const & ref ) {
> >> return( const_cast< T & >( ref ) );
> >> }


> >> With that, you could do:


> >> foo( lvalue_cast( MyClass() ) );


> > Why isn't it conforming?


> Well, there are two issues with this code.


> (a) The standard allows copying (in a non-slicing manner) of
> the object while initializing the const reference. Therefore,
> the lvalue_cast<> might not yield a reference to the temporary
> created by MyClass() but to another


Ah yes. I'd forgotten about that aspect.

> (b) Related but slightly different, the above assumes the
> existence of a copy constructor where none should be needed.


Which is a bit of a bother, since some of the most useful cases
involve classes which don't support copy (e.g. ostringstream).

> For most code those points do not matter, of course. I would
> agree that non-conforming is probably not exact. However, the
> function name creates the impression that you would get a
> reference to the object passed in; and that is not guaranteed
> (but I think it will be).


Yes. There has been some tightening down in that section.
(IIRC, the requirement for a copy constructor is also being
dropped.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
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
 
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
anonymous array of strings // ("taking address of temporary"- how long is temporary valid?) anon.asdf@gmail.com C++ 7 02-12-2008 10:58 AM
reference to the temporary object Raider C++ 3 06-22-2006 03:34 PM
Const reference to a temporary object - Why? Dave Rahardja C++ 15 11-03-2005 03:45 AM
Type conversion of reference to a temporary object Stefan Strasser C++ 2 03-28-2005 09:52 PM
A reference to non-const to be bound to a temporary object John Ky C++ 9 02-23-2004 12:53 AM



Advertisments