does this have undefined behaviour

S

subramanian100in

Consider the following code:

#include <iostream>
#include <cstdlib>

using namespace std;

int main()
{
const double& ref = 100;
double& d = const_cast<double&>(ref);
cout << d << endl;
d = 1.1;
cout << ref << endl;

return EXIT_SUCCESS;
}

In both g++ and VC++ 2005 Express Edition, the output is
100
1.1

But my doubt is: "does using 'd' invoke undefined behavior or is it
valid."

double& d = const_cast<double&>(ref);

Kindly clarify.

Thanks
V.Subramanian
 
V

Victor Bazarov

Consider the following code:

#include <iostream>
#include <cstdlib>

using namespace std;

int main()
{
const double& ref = 100;
double& d = const_cast<double&>(ref);
cout << d << endl;
d = 1.1;
cout << ref << endl;

return EXIT_SUCCESS;
}

In both g++ and VC++ 2005 Express Edition, the output is
100
1.1

But my doubt is: "does using 'd' invoke undefined behavior or is it
valid."

double& d = const_cast<double&>(ref);

What you're doing here is changing the value of the temporary
bound to a const reference. Such temporary is not const, so,
changing its value by casting away const-ness should be OK.
I can't find any place in the Standard that would prohibit
such functionality. Then my guess is that it's allowed.

V
 
W

werasm

What you're doing here is changing the value of the temporary
bound to a const reference. Such temporary is not const, so,
changing its value by casting away const-ness should be OK.
I can't find any place in the Standard that would prohibit
such functionality. Then my guess is that it's allowed.

I think the OP might have thought that he actually changed the value
of "ref" (the constant one). I don't think he realized that a
temporary was created - therefore changing the value of "d" does
not change the value of "ref".

Regards,

Werner
 
V

Victor Bazarov

werasm said:
I think the OP might have thought that he actually changed the value
of "ref" (the constant one). I don't think he realized that a
temporary was created - therefore changing the value of "d" does
not change the value of "ref".

No, that's incorrect, IMO. First off, you can't change the value
of ref because it's a reference, it doesn't really have a value
(aside from the fact that it refers to some particular object).
The temporary created is of type 'double', it has initial value
of 100.00 and it starts its lifetime just before 'ref' is bound
to it. The integral expression '100' is the initialiser for that
temporary.

The temporary to which 'ref' is bound is not a const object. It
is perfectly OK to change its value. Whether it makes sense to
do so or not is another question, but the idea is the same as in

void foo(int const& rci)
{
int& ri = const_cast<int&>(rci);
ri = 666; /// Is this OK? -- I say, yes, it is!
}

#include <iostream>
#include <ostream>
int main() {
int a = 42;
std::cout << "Before a = " << a << std::endl;
foo(a);
std::cout << "After a = " << a << std::endl;
}

V
 
A

Andre Kostur

in @i29g2000prf.googlegroups.com:
Consider the following code:

#include <iostream>
#include <cstdlib>

using namespace std;

int main()
{
const double& ref = 100;
double& d = const_cast<double&>(ref);

Dangerous. You might attempt to modify what d refers to.
cout << d << endl;
d = 1.1;

Undefined behaviour. You are modifying a const object.
cout << ref << endl;

return EXIT_SUCCESS;
}

In both g++ and VC++ 2005 Express Edition, the output is
100
1.1

But my doubt is: "does using 'd' invoke undefined behavior or is it
valid."

double& d = const_cast<double&>(ref);

This isn't Undefined Behaviour. Attempting to modify what d refers to
is the Undefined Behaviour.
 
O

Old Wolf

What you're doing here is changing the value of the temporary
bound to a const reference. Such temporary is not const, so,
changing its value by casting away const-ness should be OK.

The temporary is const. See 8.3.5#5 [dcl.init.ref], last clause.

So the behaviour is undefined when the attempt is made to
modify d (the cast itself is fine though).
 
O

Old Wolf

The temporary to which 'ref' is bound is not a const object. It
is perfectly OK to change its value.

Actually it is const, as per 8.3.5#5
the idea is the same as in

void foo(int const& rci)
{
int& ri = const_cast<int&>(rci);
ri = 666; /// Is this OK? -- I say, yes, it is!
}

#include <iostream>
#include <ostream>
int main() {
int a = 42;
std::cout << "Before a = " << a << std::endl;
foo(a);
std::cout << "After a = " << a << std::endl;
}

This code is OK; since a is an lvalue, a temporary
is not created.
 
V

Victor Bazarov

Andre said:
in @i29g2000prf.googlegroups.com:


Dangerous. You might attempt to modify what d refers to.


Undefined behaviour. You are modifying a const object.


This isn't Undefined Behaviour. Attempting to modify what d refers to
is the Undefined Behaviour.

Could you please elaborate on why it is undefined behaviour?

Thanks.

V
 
R

Rahul

The temporary to which 'ref' is bound is not a const object. It
is perfectly OK to change its value. Whether it makes sense to
do so or not is another question, but the idea is the same as in

I think, as the temp object is that of an in-built type, it is fine.
But had it been that of a custom type, the temp object would have been
an constant object...
 
V

Victor Bazarov

Rahul said:
I think, as the temp object is that of an in-built type, it is fine.
But had it been that of a custom type, the temp object would have been
an constant object...

Any standard quote to support that claim?

V
 
J

jkherciueh

Rahul said:
I think, as the temp object is that of an in-built type, it is fine.
But had it been that of a custom type, the temp object would have been
an constant object...

It's the other way around. It could work with a class type.

To provide lost context, we consider code like this:

const double& ref = 100; // *
double& d = const_cast<double&>(ref);
d = 1.1;

Clearly, line (*) is the important line. Its meaning is governed by
[8.3.5/5], which is too long to quote in full, so I cut out irrelevant
parts:

A reference to type ?cv1 T1? is initialized by an expression of type
?cv2 T2? as follows:
? If the initializer expression
? is an lvalue ...
? has a class type ... and can be implicitly converted to an lvalue ...
? Otherwise, the reference shall be to a non-volatile const type ...
? If the initializer expression is an rvalue, with T2 a class type, ...
? Otherwise, a temporary of type ?cv1 T1? is created and initialized
from the initializer expression using the rules for a non-reference
copy initialization (8.5). The reference is then bound to the
temporary. If T1 is reference-related to T2, cv1 must be the same
cv-qualification as, or greater cvqualification than, cv2; otherwise,
the program is ill-formed.

In line (*), the initializer is an rvalue not convertible to an lvalue. That
puts us in the first "Otherwise" item. Also, it is not of class type, which
puts us in the "Otherwise" subitem. The provision then states that the
const reference is bound to a temporary of type cv1 T1 (in our case that is
a temporary of type const double). Modifying that temporary under a
different handle is undefined behavior.


Now consider a class type ClassType:

const ClassType & ref = some_expression_of_ClassType;
ClassType & handle = const_cast< ClassType& >( ref );
handle = some_other_expression;

We then have the following verions of [8.5.3/5]:

A reference to type ?cv1 T1? is initialized by an expression of type
?cv2 T2? as follows:
? If the initializer expression
? is an lvalue ...
? has a class type ... and can be implicitly converted to an lvalue ...
? Otherwise, the reference shall be to a non-volatile const type ...
? If the initializer expression is an rvalue, with T2 a class type,
and ?cv1 T1? is reference-compatible with ?cv2 T2,? the reference is
bound in one of the following ways (the choice is
implementation-defined):
? The reference is bound to the object represented by the rvalue (see
3.10) or to a sub-object within that object.
? A temporary of type ?cv1 T2? [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object
within the temporary.
...
...

In this case, depending on the choice of the implementation, the reference
is either bound to a temporary of type ClassType or of type const ClassType
(if the implementation chose the second alternative). Therefore, it is
implementation-defined whether the code has undefined behavior for class
types. (I have a vague recollection that the second alternative is slanted
for elimination in the next version of the standard. In that case, the code
would have well-defined behavior for class types and undefined behavior for
built-in types.)


Best

Kai-Uwe Bux
 

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,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top