Mutability of temporary variables

K

kyle

Consider following code:

int main() {
const int& c = int();
int& m = const_cast<int&>(c);
m = 4;
}

The object of the snippet is to get a mutable reference to a temporary.
This cant be done directly because non-const reference cannot bind to
temporary, but we should be OK with casting away constness of reference
'c' since it doesn't actually refer to const object.

Temporaries are mutable, so in whole my snippet is legal C++. Am i correct?
 
V

Victor Bazarov

Consider following code:

int main() {
const int& c = int();
int& m = const_cast<int&>(c);
m = 4;
}

The object of the snippet is to get a mutable reference to a temporary.
This cant be done directly because non-const reference cannot bind to
temporary, but we should be OK with casting away constness of reference
'c' since it doesn't actually refer to const object.

Temporaries are mutable, so in whole my snippet is legal C++. Am i correct?

AIUI, your code has undefined behavior. 'c' is bound to an rvalue, and
using 'const_cast' to produce an lvalue out of it is not among the
allowed operations for 'const_cast'.

V
 
V

Victor Bazarov

Yes, I think you are correct. Another trick to get a mutable reference to
a temporary is to use a non-const member function. This avoids
const_cast, but of course lifetime extending by binding to a const
reference does not work any more:

struct A {
int m;
A& Ref() {return *this;}
};

void f(A& a) {
a.m = 4;
}

int main() {
f( A().Ref() );
}

There is a difference between your example and the OP's. In your
example the temporary is of a class type, and the expression A()
produces an lvalue to begin with.

V
 
J

Johannes Schaub

kyle said:
Consider following code:

int main() {
const int& c = int();
int& m = const_cast<int&>(c);
m = 4;
}

The object of the snippet is to get a mutable reference to a temporary.
This cant be done directly because non-const reference cannot bind to
temporary, but we should be OK with casting away constness of reference
'c' since it doesn't actually refer to const object.

The error in your thinking is that you think that "int()" is a temporary
object.

However, "int()" is not a temporary object. It is simply a value, and when
it is an initializer of a reference, a temporary object will be initialized
with that value, and the object will have the type and constness of the
referred type of the reference.

So in your case the reference refers to an object of type "const int" - you
are not allowed to modify it.
 
V

Victor Bazarov

The lvalue and rvalue notions apply to source code expressions (3.10/1:
"Every expression is either an lvalue or an rvalue"). Expression 'c' is
of a reference type, which means it is a lvalue, doesn't it? (rvalue
references use&& syntax). And lvalue->lvalue conversion is well defined
for const_cast.

Or have I misunderstood something?

int() is an rvalue expression. Now, explain that.

V
 
S

SG

There is a difference between your example and the OP's.  In your
example the temporary is of a class type, and the expression A()
produces an lvalue to begin with.

You seem to confuse two concepts, (1) value category and (2) whether
or not an expression refers to an object. There is some correlation
between these two but no equivalence. What is true though is that
every lvalue (of object type) refers to an object. But T() is always
an rvalue expression no matter what kind of object type T is (scalar
or not). Let me quote part of 3.10 of the current C++ ISO standard:

"An rvalue (...) is an xvalue, a temporary object or a subobject
thereof, or a value that is not associated with an object."

So, saying that A() is an rvalue which refers to a temporary object is
not a contradiction.

In the former version of the standard it was also clarified when an
rvalue (that is not an xvalue) actually refers to an object and when
not. I can't find it in the current incarnation but I guess it did not
change. PRvalues of _scalar_types_ are not associated with an object,
they are just "values". And since int is a scalar type int() does not
refer to an object (temporary or otherwise). But of course, a
reference of object type has to refer to an object. That's why a
temporary object is created as part of the reference initialization
procedure.

I suggest to look up §3.10 and the part about reference initialization
in both versions of the C++ ISO standard.

Cheers!
SG
 
S

SG

int main() {
   const int& c = int();
   int& m = const_cast<int&>(c);
   m = 4;
}

[...]

Temporaries are mutable, so in whole my snippet is legal C++. Am i correct?

Yes, I believe so. I would not go as far as saying "temporaries are
mutable" because one can easily create const class-type temporaries.
These are obviously not mutable unless they have mutable data members.
But, I agree with Paavo on this one. As far as I can tell, no
undefined behaviour is invoked here.

Cheers!
SG
 
J

Johannes Schaub

SG said:
int main() {
const int& c = int();
int& m = const_cast<int&>(c);
m = 4;
}

[...]

Temporaries are mutable, so in whole my snippet is legal C++. Am i
correct?

Yes, I believe so. I would not go as far as saying "temporaries are
mutable" because one can easily create const class-type temporaries.
These are obviously not mutable unless they have mutable data members.
But, I agree with Paavo on this one. As far as I can tell, no
undefined behaviour is invoked here.

What do you say about the point I have made about the code?
 
K

kyle

Dnia 19-11-2011 o 16:16:45 Johannes Schaub
The error in your thinking is that you think that "int()" is a temporary
object.

This is indeed what i assumed.
As i understand, i could 'fix' the code by having a function 'int foo()
{return 1;}' and using it in place of 'int()'?

Unfortunately, what i originally planned to do is illegal for entirely
different reason ;)
 
J

Johannes Schaub

kyle said:
Dnia 19-11-2011 o 16:16:45 Johannes Schaub


This is indeed what i assumed.
As i understand, i could 'fix' the code by having a function 'int foo()
{return 1;}' and using it in place of 'int()'?

No, as someone else already said, rvalues of non-class and non-array type
are not objects, and the rules for initialization of references adequately
are worded to take that into account. It will behave exactly like the
"int()" case.
 

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,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top