Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > GotW #88: Is it safe to const_cast a reference to a temporary?

Reply
Thread Tools

GotW #88: Is it safe to const_cast a reference to a temporary?

 
 
James Kanze
Guest
Posts: n/a
 
      02-04-2008
On Feb 3, 8:08 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:
> > On Feb 3, 3:55 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * James Kanze:
> >>> On Feb 2, 10:37 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >>>> * Niels Dekker - no return address:


> >>>>> Herb Sutter wrote a new Guru-of-the-Week column last month, GotW #88,
> >>>>> about binding a temporary object to a reference-to-const. Now if this
> >>>>> temporary isn't const, is it safe to const_cast the reference?


> >>>>> #include <string>
> >>>>> #include <cassert>
> >>>>> using std::string;


> >>>>> string f() { return "abc"; }


> >>>>> void h() {
> >>>>> const string& s1 = f();
> >>>>> const string& s2 = s1;
> >>>>> const_cast<string&>(s1) = "new value!"; // Safe?


> >>>> Not in standard C++, although it might be safe with a
> >>>> particular compiler.


> >>> This has always been my believe as well, and I'm almost sure
> >>> that I once read somewhere in the standard something to the
> >>> effect that any attempt to modify a temporary (e.g. by such
> >>> tricks) was undefined behavior. The last time I looked for it,
> >>> however, I couldn't find it. So could you tell me where in the
> >>> standard this is forbidden.


> >> Yes. With respect to the 1998 standard there are two rules
> >> involved: first, a rule saying that modifying a (we must
> >> presume "original" is meant) const object incurs Undefined
> >> Behavior, §7.1.5.1/4, and second, a rule that that the
> >> reference can be, at the implementation's discretion, a
> >> reference to an original const object (a new const temporary
> >> that is copy constructed from the initializer), §8.5.3/5.


> > I don't see where "orignal" is relevant. This rule concerns the
> > object itself, and not the type of expression used to refer to
> > it. In the sample code above, none of the objects are const.
> > That is, IMHO, the crux of the problem.


> No, the reference's type -- its cv-qualification -- is very
> relevant because the cv-qualification can be transferred to a
> temporary created for the purpose, and no, it's not the case
> that one is guaranteed that none of the objects are const, in
> the code above.


> Trying to be utterly unambigiously clear:


> §5.1.3/5
> "A reference to type "cv1 T1" is initialized by an expression of
> type "cv2 T2" as follows:


> ...


> - Otherwise, the reference shall be to a non-volatile const type
> (i.e. cv1 shall be const)
> [Example: ...]


> - 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 into the temporary. The
> reference is bound to the temporary or to sub-object within
> the temporary.


> The last alternative above


Which is a point I'd definitely overlooked. Of course, this
alternative has been dropped from the latest draft.

> is the one that, together with UB for modification of const,
> dictates UB for the example code. And what happens in this
> case is that "cv1" is "const", from the declaration of the
> /reference/ s1, "T2" is "string", from the declaration of f(),
> and the type of the temporary created is then "const string"
> -- which is not a typo, but intentional ([sic] means
> essentially that "this is /not/ a typo"). This is then what
> the reference is bound to when this case is chosen, namely a
> new temporary of type "const string".


Yep. That one character (a 1 instead of a 2) makes a world of
difference here.

> And the pure possibility of that alternative being chosen, and
> that alternative implying UB, means that formally the code is
> UB.


Agreed. (That's another thing I'm 100% sure of, but don't know
off hand where to find it in the standard. But of course,
nothing else would make sense.)

I wonder if the committee realizes that by dropping this
alternative, they're suddenly making undefined behavior defined.

> > (And I very definitely
> > remember reading somewhere that attempting to modify an
> > rvalue---or maybe it was only an rvalue of non-class type---was
> > undefined behavior, regardless of the const.)


> For rvalue of non-class type yes I think so, but for rvalue of
> class type, no, quite the opposite.


> But I've done enough standardeeze for today, I think.


I'll admit that in this case, it's rather sterile. Because even
if all this were perfectly defined, I still wouldn't want to see
it in actual code.

I think, however, that I'll raise the question on the reflectors
(since comp.std.c++ seems rather dead at the moment). I
certainly wouldn't mind seeing a phrase added to the effect that
any attempt to modify an rvalue bound to a reference is
undefined behavior. (Reminds me too much of some early
Fortrans, where f(0) might actually call f() with 1 as an
argument, if a previous call to f() had modified the value.)

--
James Kanze (GABI Software) email:
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
 
 
 
 
Niels Dekker - no return address
Guest
Posts: n/a
 
      02-04-2008
James Kanze wrote:
> I think, however, that I'll raise the question on the reflectors
> (since comp.std.c++ seems rather dead at the moment). I
> certainly wouldn't mind seeing a phrase added to the effect that
> any attempt to modify an rvalue bound to a reference is
> undefined behavior.


Would that include modifying a *mutable* data member of an rvalue?

Anyway, I just added a link to this discussion on Herb Sutter's blog:
http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry
Thanks for your feedback!

Niels
 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-04-2008
* Niels Dekker - no return address:
> James Kanze wrote:
>> I think, however, that I'll raise the question on the reflectors
>> (since comp.std.c++ seems rather dead at the moment). I
>> certainly wouldn't mind seeing a phrase added to the effect that
>> any attempt to modify an rvalue bound to a reference is
>> undefined behavior.

>
> Would that include modifying a *mutable* data member of an rvalue?


The question is one of supporting or not optimizations based on the
compiler knowing that a value can't be modified without UB. So
presumably the rule should simply be that the object referred to by an
ordinary reference bound to an rvalue, is regarded as a const object
(originally const object) with regard to later access. Then modifying a
mutable member would be OK, and this rule would just reinstate the
relevant part of the rule that was removed in the C++0x draft.

Just my 2c,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-04-2008
* Niels Dekker - no return address:
>
> Anyway, I just added a link to this discussion on Herb Sutter's blog:
> http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry
> Thanks for your feedback!


Niels, could you please add a comment for me (that darned system
requires some "Windows Live ID" whatever the heck that is):

Herb's attribution/credit for ScopeGuard is incorrect.

It was Petru Marginean's child, not Andrei Alexandrescu's.

Though Andrei helped add another abstraction layer, and co-authored the
DDJ article (I think it was DDJ, unless it was C/C++ User's Journal).


Cheers, & a bit frustrated, & TIA.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
steady.li@gmail.com
Guest
Posts: n/a
 
      02-05-2008
by the way , I tested what you are dicussing using VC2005 but find
another problem that confused me. who can help me understand it?

int a = 1;
const int& b= 1; // legal //using the mechanism is using const
reference to temporary.
//int& c = 1; //illegal // why? but according to what you talked ,
it is not the rule though, it can
be supported by VS2005, just like
string& s1 = f();
int& d= a; //legeal
const int& e = a; //legal // why it is legal? const reference also
can point to non-const content memory?
int& f = b; //ilegal; from const to non-const error

 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-05-2008
* :
> by the way , I tested what you are dicussing using VC2005 but find
> another problem that confused me. who can help me understand it?
>
> int a = 1;
> const int& b= 1; // legal //using the mechanism is using const
> reference to temporary.
> //int& c = 1; //illegal // why? but according to what you talked ,
> it is not the rule though, it can
> be supported by VS2005, just like


I think you mean, why is it disallowed by the standard, when there
exists at least one compiler that does support it (for class type
objects) as a language extension, showing by example that it could in
principle be allowed.

One example is

void foo( int& x ) { x = 666; }

int main()
{
foo( 42 );
}

One would want this to not compile.

Another example involves implicit type conversion, where the object
modified is not the actual argument but a temporary created from the
actual argument. One would want that also to not compile, instead of
silently doing nothing. However, the problem could be avoided by
disallowing automatic creation of a temporary for such arguments.

The short summary is that disallowing that binding is practically
useful, whereas allowing it (as it was originally) turned out to create
a host of problems.

The Annotated Reference Manual (a.k.a. the "ARM") says of the earlier
more permissive rule that it was "a major source of errors and surprises".


> string& s1 = f();


This is invalid unless f() returns a reference or an object convertible
to reference.


> int& d= a; //legeal
> const int& e = a; //legal // why it is legal? const reference also
> can point to non-const content memory?


Yes. It doesn't make that object const in itself. It just restricts
what you can do with the object via the reference.


Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Niels Dekker - no return address
Guest
Posts: n/a
 
      02-05-2008
>> Anyway, I just added a link to this discussion on Herb Sutter's blog:
>> http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry


Alf P. Steinbach wrote:
> Niels, could you please add a comment for me (that darned system
> requires some "Windows Live ID" whatever the heck that is):
>
> Herb's attribution/credit for ScopeGuard is incorrect.
> It was Petru Marginean's child, not Andrei Alexandrescu's.
>
> Though Andrei helped add another abstraction layer, and co-authored the
> DDJ article (I think it was DDJ, unless it was C/C++ User's Journal).


I'm sorry for you but it's not such a big deal to me. There's a link to
the article by Andrei and Petru on Herb's blog entry. And there's a
link from his page to this newsgroup thread as well, by now. So a
reader of Herb's blog can easily find out that the ScopeGuard is
originally from Petru...

If you still think Herb's blog should explicitly mention Petru (which
would of course be more correct), why don't you just send him an
e-mail? His mail address is at www.gotw.ca. Otherwise just get
yourself that "Windows Live ID", whatever the heck. You can get it for
free, at least if you're willing to give some of your personal
information to Microsoft...

Hope that helps,

Thanks again for your feedback,

--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center
 
Reply With Quote
 
Niels Dekker - no return address
Guest
Posts: n/a
 
      02-06-2008
Alf P. Steinbach wrote:
> Herb's attribution/credit for ScopeGuard is incorrect.
> It was Petru Marginean's child, not Andrei Alexandrescu's.


He just fixed it Cool!
http://herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry

-- Niels
 
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
stock unwinding from GotW #47 puzzlecracker C++ 0 05-01-2008 02:35 PM
Challenging GotW 66's moral George2 C++ 4 12-27-2007 05:48 PM
Doubt in GotW #27 - forwarding functions Srini C++ 5 09-10-2005 10:26 PM
const_cast question drowned C++ 3 08-04-2003 08:51 AM
[help] const_cast Kaspar Minosiants C++ 2 07-21-2003 12:43 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57