non-const reference to temporary object

R

rajath575

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?
 
R

Rolf Magnus

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.
 
S

Salt_Peter

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
}
 
K

Kai-Uwe Bux

Salt_Peter said:
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
 
J

James Kanze

On Nov 26, 11:00 pm, (e-mail address removed) wrote:
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.
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.
 
J

James Kanze


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.
 
K

Kai-Uwe Bux

James said:
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
 
K

Kai-Uwe Bux

James Kanze wrote:

...]
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
 
R

rajath575

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.
 
J

James Kanze

James Kanze wrote:
[..]
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.)
 
J

James Kanze

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.

Yes and no. The question in this case is why a function which
writes the object to a file takes a non-const reference.
 

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

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top