Temporaries, non-const yet r-value?!

J

JKop

Firstly, we all know that temporaries are non-const, which I shall
demonstrate with the following code:

struct Blah
{
int monkey;

void SetMonkey(int const supplied)
{
monkey = supplied;
}
};


Blah SomeFunc()
{
return Blah();
}


int main()
{
Blah().SetMonkey(5);

SomeFunc().monkey = 5;
}


But, at the same time, temporaries are "r-value"'s. The following is
illegal:

int Blah()
{
return 5;
}

int main
{
Blah() = 6;
}


Also, in the previous code, "Blah().monkey = 5" is illegal.


It's not legal to bind a temporary to a non-const reference, because it is
an "r-value".


You're allowed to use "const_cast" to cast away the constness if the
original object was in fact non-const...

struct Blah
{
int a;
double b;
char c;
float** p_p_f;
wchar_t k;
bool f;
};

int main()
{
Blah const &poo = Blah();

Blah &cow = const_cast<Blah&>(poo);

cow.a = 5;
}



Any thoughts on this?


-JKop
 
A

Alf P. Steinbach

* JKop:
Any thoughts on this?

It's a correct observation. And yes it's problematic. The Mojo article
that (now long ago, measured in software development time) started the
current debate:
<url: http://www.cuj.com/documents/s=8246/cujcexp2102alexandr/alexandr.htm>.

And recently in this forum Chris Theis raised the question of what's
happened since then.

That's a new thread NRVO in [comp.std.c++], but very little concrete
has been forthcoming.
 
R

Rob Williscroft

JKop wrote in in comp.lang.c++:
You're allowed to use "const_cast" to cast away the constness if the
original object was in fact non-const...

Thats correct, but ...
struct Blah
{
};

int main()
{
Blah const &poo = Blah();

The problem is here, the rvalue is allowed to bind via a temporary
and although we all know that the temp will in reality (*) be no
more constant than the rvalue, the standard allows it to be.

*) Here: reality == Desktop PC's

So the actual object "poo" refers to is a real constant.
Blah &cow = const_cast<Blah&>(poo);

That is OK, but ...
cow.a = 5;

That is UB.

Microsofts VC++ has a mode where it check's (at runtime) for
buffer overflows, such a system could also be used to check for
the constantness of the temp "poo" was bound too, and your code
nolonger works.

Also in this case, since the "Blah" that was used is a value
initialized POD, the constant could actualy be in read-only
memory, bang goes your code again (or maybe it doesn't compile).

Rob.
 
R

Ron Natalie

The problem is here, the rvalue is allowed to bind via a temporary
and although we all know that the temp will in reality (*) be no
more constant than the rvalue, the standard allows it to be.

No it does not. Temporaries are not necessarily const. A temporary
of class type can be modified.
That is OK, but ...




That is UB.
No.

Also in this case, since the "Blah" that was used is a value
initialized POD, the constant could actualy be in read-only
memory, bang goes your code again (or maybe it doesn't compile).

No.
 
R

Rob Williscroft

Ron Natalie wrote in in
comp.lang.c++:
No it does not.

Your right it doesn't allow it, it *requires* it:

8.5.3/5:

The relevent bit:

— 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.93)
Temporaries are not necessarily const. A temporary
of class type can be modified.


No.

Yes, Yes.

Rob.
 
V

Victor Bazarov

Rob said:
Ron Natalie wrote in in
comp.lang.c++:




Your right it doesn't allow it, it *requires* it:

Did you miss the "one of the following ways (the choice is implementation-
defined" a few lines above the quoted section?
8.5.3/5:

The relevent bit:

— 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.93)

Temporaries are not necessarily const. A temporary
of class type can be modified.




No.


Yes, Yes.

NO NO

Victor
 
R

Rob Williscroft

Victor Bazarov wrote in
in
comp.lang.c++:
Did you miss the "one of the following ways (the choice is
implementation- defined" a few lines above the quoted section?

Thats " ... the rvalue is alowed to bind via a temporary ... " as I
said above, but if it does the temporary is *required* to be const.

Rob.
 
V

Victor Bazarov

Rob said:
Victor Bazarov wrote in
in
comp.lang.c++:




Thats " ... the rvalue is alowed to bind via a temporary ... " as I
said above, but if it does the temporary is *required* to be const.

Ah, sorry, I didn't understand what you were hinting at. Yes, if the
temporary _is_ created, that temporary will be const. It doesn't have
to be created, though.

So, using the original example

Blah const &poo = Blah();
Blah &cow = const_cast<Blah&>(poo);
cow.a = 5;

the behaviour is NOT undefined, but rather _implementation_defined_. That
is because the 'poo' reference _may_ bind to the original temporary and
not to an intermediate one.

Victor
 
R

Rob Williscroft

Victor Bazarov wrote in
in
comp.lang.c++:
Ah, sorry, I didn't understand what you were hinting at. Yes, if the
temporary _is_ created, that temporary will be const. It doesn't have
to be created, though.

So, using the original example

Blah const &poo = Blah();
Blah &cow = const_cast<Blah&>(poo);
cow.a = 5;

the behaviour is NOT undefined, but rather _implementation_defined_.
That is because the 'poo' reference _may_ bind to the original
temporary and not to an intermediate one.

Yes, but what is implementation defined here is wether UB happens
or not. IMO that is UB (the same as n * 0 == 0 for any n). YMMV.

Rob.
 
M

Mike Wahler

Rob Williscroft said:
Victor Bazarov wrote in
in
comp.lang.c++:


Yes, but what is implementation defined here is wether UB happens
or not. IMO that is UB (the same as n * 0 == 0 for any n). YMMV.

But is UB * 0 always == 0 ???

-:)

-Mike
 
R

Rob Williscroft

Mike Wahler wrote in @newsread1.news.pas.earthlink.net in comp.lang.c++:
But is UB * 0 always == 0 ???

-:)

Yep I think so:

void f()
{
char *s = new char[10];
delete s;
}

int main()
{
}

f() exhibts UB but its called 0 times so the programme
doesn't exhibit UB.

<SCNR mode="daft-as-brush">

Of course UB is calculated using signed maginitude and we have
+ve and -ve 0;

implementation-defined * UB == UB ( greater-than-0 * -0 == -0 ) (*)

and

UB * don't-do-it-it-hurts == don't-do-it-it-hurts ( -0 * +0 == +0 ) (*).

*) Note: I've no idea if signed magnitude CPU's actualy work this way :)

</SCNR>

:)

Rob.
 

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,969
Messages
2,570,161
Members
46,710
Latest member
bernietqt

Latest Threads

Top