Topic: operator class&() { return *this; } considered harmful?
Author: Michael Norrish <michael.norrish@nicta.com.au>
Date: Tue, 6 Nov 2007 16:48:46 CST Raw View
Greg Herlihy wrote:
> There is little point in defining a conversion to a reference of the
> same class type - because an object can always be used to initialize
> a reference of its own type.
Surely not. An object can always be used to initialise a *const*
reference of its own type.
> In other words, adding the C&() operator has no real effect on the
> program (except to make it more difficult for the compiler to warn
> that the function f() is returning a reference to a de-allocated
> object.)
f() wasn't returning a reference: it returned an r-value object. I
then wanted to convert it into a reference using the conversion
function precisely so that I could initialise a non-const reference.
This would exercise the language at the head of 8.5.3/5.
> Moreover, having f() return a C object by value would not only be
> safe, but would also be slightly more efficient than the current
> implementation of f() (owing to the Named Return Value
> Optimization).
The original f was
C f()
{
C temp(2);
return temp;
}
followed by
int main()
{
C &x = f();
...
}
Without the operator C&() member in C, this initialisation is
rejected.
Michael.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Michael Norrish <michael.norrish@nicta.com.au>
Date: Tue, 6 Nov 2007 17:29:09 CST Raw View
Alberto Ganesh Barbati wrote:
>>> If this is so, is there any point to the language in 8.5.3/5
>>> allowing this? (This language is "if the initializer expression
>>> ... has a class type ... and can be implicitly converted to an
>>> lvalue....". The footnote emphasises that this situation can only
>>> arise when you have a conversion function returning a reference
>>> type.)
> Notice that in this case "the reference is bound to the lvalue
> result of the conversion" confirming my interpretation.
I'm quite willing to believe your interpretation (and your example
below demonstrates the language in the relevant clause is still
useful), but to quibble on a tangent: if you have an
operator C&()
around, then surely its application to an r-value will still return an
l-value? In other words, if you have a reference, however dubiously
derived, doesn't that mean you then have an l-value?
> The fault in your reasoning is that it's not true that the initializer
> must be an temporary to trigger this case. Consider this:
> class B;
> class A
> {
> public:
> operator B& ();
> };
> A a;
> B& b = a;
> In fact, this example shows a very good reason why this case is
> allowed.
Indeed! Thanks for this example.
Michael.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: Wed, 7 Nov 2007 16:08:57 CST Raw View
Michael Norrish ha scritto:
> Alberto Ganesh Barbati wrote:
>> Michael Norrish ha scritto:
>>> Clearly, the rvalue reference proposal solves all sorts of other
>>> interesting issues apart from the one in my example, but my question
>>> is really whether or not
>>>
>>> operator C&() { return *this; }
>>>
>>> will safely achieve what I want.
>>>
>>
>> I don't think so. According to my interpretation, 12.2/5 doesn't apply
>> here, because in line:
>>
>> C &x = f();
>>
>> the reference x is *not* bound to a temporary, but rather to the result
>> of the call to operator C& which is a reference (such reference
>> *happens* to be bound to a temporary but this fact is irrelevant to a
>> strict interpretation of 12.2/5).
>>
>> I expect the temporary to be properly destroyed at the end of the
>> full-expression, making x a dangling reference.
>
> If this is so, is there any point to the language in 8.5.3/5 allowing
> this? (This language is "if the initializer expression ... has a
> class type ... and can be implicitly converted to an lvalue....". The
> footnote emphasises that this situation can only arise when you have a
> conversion function returning a reference type.)
Notice that in this case "the reference is bound to the lvalue result of
the conversion" confirming my interpretation.
> That clause only applies when the initialisor is not an lvalue, so
> there will be a temporary here anyway. That temporary can only get
> turned into an l-value via a conversion function, but if you are
> right, then the conversion function can't usefully return a reference
> to the temporary it's called on because that temporary will disappear
> as soon as the declaration of the reference completes. (The
> conversion function could return a reference to something other than
> the temporary of course; some global perhaps).
The fault in your reasoning is that it's not true that the initializer
must be an temporary to trigger this case. Consider this:
class B;
class A
{
public:
operator B& ();
};
A a;
B& b = a;
In fact, this example shows a very good reason why this case is allowed.
HTH,
Ganesh
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: greghe@mac.com (Greg Herlihy)
Date: Fri, 2 Nov 2007 05:33:54 GMT Raw View
On 10/30/07 11:18 PM, in article 4727ef35$1@clarion.carno.net.au, "Michael
Norrish" <michael.norrish@nicta.com.au> wrote:
> Alberto Ganesh Barbati wrote:
>> Michael Norrish ha scritto:
>>> Clearly, the rvalue reference proposal solves all sorts of other
>>> interesting issues apart from the one in my example, but my question
>>> is really whether or not
>>>
>>> operator C&() { return *this; }
>>>
>>> will safely achieve what I want.
>>>
>>
>> I don't think so. According to my interpretation, 12.2/5 doesn't apply
>> here, because in line:
>>
>> C &x = f();
>>
>> the reference x is *not* bound to a temporary, but rather to the result
>> of the call to operator C& which is a reference (such reference
>> *happens* to be bound to a temporary but this fact is irrelevant to a
>> strict interpretation of 12.2/5).
>>
>> I expect the temporary to be properly destroyed at the end of the
>> full-expression, making x a dangling reference.
>
> If this is so, is there any point to the language in 8.5.3/5 allowing
> this? (This language is "if the initializer expression ... has a
> class type ... and can be implicitly converted to an lvalue....". The
> footnote emphasises that this situation can only arise when you have a
> conversion function returning a reference type.)
There is little point in defining a conversion to a reference of the same
class type - because an object can always be used to initialize a reference
of its own type. In other words, adding the C&() operator has no real effect
on the program (except to make it more difficult for the compiler to warn
that the function f() is returning a reference to a de-allocated object.)
Moreover, having f() return a C object by value would not only be safe, but
would also be slightly more efficient than the current implementation of f()
(owing to the Named Return Value Optimization).
Greg
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Fri, 2 Nov 2007 16:54:13 GMT Raw View
[Note to mods: this is a repost. Although the previous post had been
approved, it somehow didn't appear on the newsgroup.]
Michael Norrish ha scritto:
> > Alberto Ganesh Barbati wrote:
>> >> Michael Norrish ha scritto:
>>> >>> Clearly, the rvalue reference proposal solves all sorts of other
>>> >>> interesting issues apart from the one in my example, but my question
>>> >>> is really whether or not
>>> >>>
>>> >>> operator C&() { return *this; }
>>> >>>
>>> >>> will safely achieve what I want.
>>> >>>
>> >>
>> >> I don't think so. According to my interpretation, 12.2/5 doesn't apply
>> >> here, because in line:
>> >>
>> >> C &x = f();
>> >>
>> >> the reference x is *not* bound to a temporary, but rather to the
result
>> >> of the call to operator C& which is a reference (such reference
>> >> *happens* to be bound to a temporary but this fact is irrelevant to a
>> >> strict interpretation of 12.2/5).
>> >>
>> >> I expect the temporary to be properly destroyed at the end of the
>> >> full-expression, making x a dangling reference.
> >
> > If this is so, is there any point to the language in 8.5.3/5 allowing
> > this? (This language is "if the initializer expression ... has a
> > class type ... and can be implicitly converted to an lvalue....". The
> > footnote emphasises that this situation can only arise when you have a
> > conversion function returning a reference type.)
Notice that in this case "the reference is bound to the lvalue result of
the conversion" confirming my interpretation.
> > That clause only applies when the initialisor is not an lvalue, so
> > there will be a temporary here anyway. That temporary can only get
> > turned into an l-value via a conversion function, but if you are
> > right, then the conversion function can't usefully return a reference
> > to the temporary it's called on because that temporary will disappear
> > as soon as the declaration of the reference completes. (The
> > conversion function could return a reference to something other than
> > the temporary of course; some global perhaps).
The fault in your reasoning is that it's not true that the initializer
must be an temporary to trigger this case. Consider this:
class B;
class A
{
public:
operator B& ();
};
A a;
B& b = a;
In fact, this example shows a very good reason why this case is allowed.
HTH,
Ganesh
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: michael.norrish@nicta.com.au (Michael Norrish)
Date: Tue, 30 Oct 2007 05:22:56 GMT Raw View
I was wondering if there were any serious gotchas with including a
conversion to class& in a class's public interface.
Consider
#include <iostream>
using namespace std;
class C {
int fld;
public:
C(int x) : fld(x) {}
C(const C &r) : fld(r.fld) {}
int get_val() { return fld; }
operator C&() { return *this; }
};
C f()
{
C temp(2);
return temp;
}
int main()
{
C &x = f();
cout << "x = " << x.get_val() << endl;
return 0;
}
Without the operator C&, I can't initialise the reference x in main
(by 8.5.3, para 5). But with it in place, it seems to me as if the
language in 12.2 para 5 then guarantees that the object nominally
allocated in f will actually have a lifetime equivalent to the scope
of main's body.
But maybe there's something I'm missing?
Thanks,
Michael.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: =?iso-8859-1?q?Pedro_Lamar=E3o?= <pedro.lamarao@gmail.com>
Date: Tue, 30 Oct 2007 11:56:41 CST Raw View
On 30 out, 03:22, michael.norr...@nicta.com.au (Michael Norrish)
wrote:
> I was wondering if there were any serious gotchas with including a
> conversion to class& in a class's public interface.
>
> Consider
>
> #include <iostream>
> using namespace std;
>
> class C {
> int fld;
> public:
> C(int x) : fld(x) {}
> C(const C &r) : fld(r.fld) {}
> int get_val() { return fld; }
> operator C&() { return *this; }
>
> };
>
> C f()
> {
> C temp(2);
> return temp;
>
> }
>
> int main()
> {
> C &x = f();
> cout << "x = " << x.get_val() << endl;
> return 0;
>
> }
>
> Without the operator C&, I can't initialise the reference x in main
> (by 8.5.3, para 5). But with it in place, it seems to me as if the
> language in 12.2 para 5 then guarantees that the object nominally
> allocated in f will actually have a lifetime equivalent to the scope
> of main's body.
>
> But maybe there's something I'm missing?
You are missing rvalue references.
int main()
{
C&& x = f();
cout << "x = " << x.get_val() << endl;
return 0;
}
This new kind of reference is now part of the draft standard.
This is the explanatory paper:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html
This is the last paper with proposed wording before inclusion in the
draft:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
--
Pedro Lamar o
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: michael.norrish@nicta.com.au (Michael Norrish)
Date: Tue, 30 Oct 2007 22:13:25 GMT Raw View
Pedro Lamar=E3o wrote:
> On 30 out, 03:22, michael.norr...@nicta.com.au (Michael Norrish)
> wrote:
> You are missing rvalue references.
> int main()
> {
> C&& x =3D f();
> cout << "x =3D " << x.get_val() << endl;
> return 0;
> }
> This new kind of reference is now part of the draft standard.
Clearly, the rvalue reference proposal solves all sorts of other
interesting issues apart from the one in my example, but my question
is really whether or not
operator C&() { return *this; }
will safely achieve what I want.
Best,
Michael.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Alberto Ganesh Barbati <AlbertoBarbati@libero.it>
Date: Tue, 30 Oct 2007 18:07:44 CST Raw View
Michael Norrish ha scritto:
>
> Clearly, the rvalue reference proposal solves all sorts of other
> interesting issues apart from the one in my example, but my question
> is really whether or not
>
> operator C&() { return *this; }
>
> will safely achieve what I want.
>
I don't think so. According to my interpretation, 12.2/5 doesn't apply
here, because in line:
C &x = f();
the reference x is *not* bound to a temporary, but rather to the result
of the call to operator C& which is a reference (such reference
*happens* to be bound to a temporary but this fact is irrelevant to a
strict interpretation of 12.2/5).
I expect the temporary to be properly destroyed at the end of the
full-expression, making x a dangling reference.
Just my opinion,
Ganesh
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Michael Norrish <michael.norrish@nicta.com.au>
Date: Wed, 31 Oct 2007 00:18:25 CST Raw View
Alberto Ganesh Barbati wrote:
> Michael Norrish ha scritto:
>> Clearly, the rvalue reference proposal solves all sorts of other
>> interesting issues apart from the one in my example, but my question
>> is really whether or not
>>
>> operator C&() { return *this; }
>>
>> will safely achieve what I want.
>>
>
> I don't think so. According to my interpretation, 12.2/5 doesn't apply
> here, because in line:
>
> C &x = f();
>
> the reference x is *not* bound to a temporary, but rather to the result
> of the call to operator C& which is a reference (such reference
> *happens* to be bound to a temporary but this fact is irrelevant to a
> strict interpretation of 12.2/5).
>
> I expect the temporary to be properly destroyed at the end of the
> full-expression, making x a dangling reference.
If this is so, is there any point to the language in 8.5.3/5 allowing
this? (This language is "if the initializer expression ... has a
class type ... and can be implicitly converted to an lvalue....". The
footnote emphasises that this situation can only arise when you have a
conversion function returning a reference type.)
That clause only applies when the initialisor is not an lvalue, so
there will be a temporary here anyway. That temporary can only get
turned into an l-value via a conversion function, but if you are
right, then the conversion function can't usefully return a reference
to the temporary it's called on because that temporary will disappear
as soon as the declaration of the reference completes. (The
conversion function could return a reference to something other than
the temporary of course; some global perhaps).
Michael.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]