Topic: Binding temp rvalue to non const reference


Author: Howard Hinnant <hinnant@antispam.twcny.rr.com>
Date: Wed, 18 Jul 2001 20:56:29 GMT
Raw View
In article <memo.20010717213651.64201E@brangdon.madasafish.com>, Dave
Harris <brangdon@cix.co.uk> wrote:

| I disagree. I see an analogy with the function return value. The author of
| the function makes it available, but the client decides whether to use it
| or not. If we can ignore return values we should be able to ignore "out"
| parameters too. The decision belongs in the client code.
|
| Even if the author thinks it is not safe, the most she can do is force the
| client to bind a named variable. That doesn't guarantee that the client
| will inspect its value.

At least this forces the client to think about the issue.

I think we will have to agree to disagree.  And while I'm at it, I
think I'll disagree with myself as well. :-)  I've changed my mind
about the value of the temp& qualifier.

Instead I think it would be sufficient to decide in favor of point #2
in cwg open issue 214
(http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/cwg_active.html#214).  This
will allow method designers to "bind" to temporaries when they really
want to, without binding to a const lvalue, via a "move" facility
(which could be made standard).  Such a facility would dissallow moving
from temporaries created via implicit conversions which I believe would
be agreeable.  But it would still allow moving from temporaries created
via explicit conversions.

Here's prototype code which exercises 3 types of methods:

   1.  Read only (inspect argument)
   2.  Read/Write (output info through argument)
   3.  Destructive read of argument (arg can be temporary, but not
const)

These methods deal with an example class A.  They are also tested
against a class I which will implicitly convert to A, and a class E
which will explicitly convert to A.  const and non-const parameters of
each type are passed:

template <class T>
struct move_t
{
   move_t(T& t) : ptr_(&t) {}
   T* ptr_;
};

template <class T>
inline
move_t<T>
move(T& t)
{
   return move_t<T>(t);
}

template <class T>
inline
move_t<T>
move(T t)  // binds only to rvalues because of T& overload
{
   return move(t);  // calls move(T&)
}

struct I
{
};

struct E
{
};

struct A
{
   A() {}
   A(I) {}
   explicit A(E) {}
   A(const A&) {}
   ~A() {}
   void extract() {}
};

struct Z
{
   void inspect(const A&) {}
   void modify(A&) {}
   void move_info_from(move_t<A> m) // bind to non-const or temp A
      {m.ptr_->extract();}
};

int main()
{
   A a;
   A const ac = A();
   I i;
   I const ic = I();
   E e;
   E const ec = E();
   Z z;

   z.inspect(a);            // ok
   z.inspect(ac);           // ok
   z.inspect(i);            // ok
   z.inspect(ic);           // ok
   z.inspect(A(e));         // ok
   z.inspect(A(ec));        // ok

   z.modify(a);             // ok
// z.modify(ac);            // error
// z.modify(i);             // error
// z.modify(ic);            // error
// z.modify(A(e));          // error
// z.modify(A(ec));         // error

   z.move_info_from(move(a));     // ok
// z.move_info_from(move(ac));    // error
// z.move_info_from(move(i));     // error
// z.move_info_from(move(ic));    // error
   z.move_info_from(move(A(e)));  // ok
   z.move_info_from(move(A(ec))); // ok
}

In this system, both class designer and class client must cooperate to
"bind" a temporary to a non-const parameter.

The class designer must provide a move_t<A> as the argument type,
signifying the desire to bind to a temporary despite the destructive
nature of the method.

The class client must use move, signalling and documenting knowledge
that the parameter may (will?) be modified, even though it can be a
temp.

All of this should be qualified as highly experimental as the effects
of having both:

template <class T> move_t<T> move(T&);
template <class T> move_t<T> move(T);

are still under debate by the cwg.  I would be very interested in the
comments of those language lawyers familiar with this part of issue
214.  (I am not familiar with this issue)

--
Howard Hinnant

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Mon, 23 Jul 2001 13:34:10 CST
Raw View
hinnant@antispam.twcny.rr.com (Howard Hinnant) wrote (abridged):
> I think we will have to agree to disagree.

I guess so. I think we have different aims and perspectives.

I see the issue as not being so much about temporaries as about
expressions (which evaluate to temporaries). And I think expressions are
important to, well, expressiveness. That's my perspective.

My aim is to be able to write things like 3 + 4 * 5 + 6 without having to
name all the intermediates, and I want that for user-defined types as well
as ints and without loss of efficiency.


> In this system, both class designer and class client must cooperate to
> "bind" a temporary to a non-const parameter.

As written, the syntax strikes me as being too heavy weight on the client
side for every day use. Having to wrap intermediate expressions with
"move" is only a small improvement on having to give them names. On the
class designer side, the fact that it needs upfront cooperation from the
designer limits its applicability.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Howard Hinnant <hinnant@antispam.twcny.rr.com>
Date: Mon, 16 Jul 2001 19:30:45 GMT
Raw View
In article <slrn.pl.9l6a7a.lkc.qrczak@qrnik.zagroda>, Marcin 'Qrczak'
Kowalczyk <qrczak@knm.org.pl> wrote:

| If an lvalue is being implicitly converted, it looks like the specified
| object was being modified, but in reality it's not. Introducing
| an implicit conversion changes the meaning completely - object
| identity was important, not only value, and this doesn't play well
| with implicit conversions which might more or less preserve the value
| but will definitely change the identity.

I'm concerned about this case:

struct Base
{
   /*
      some information
   */

   void destructive_read(Base temp&);  // imaginary temp& syntax
};

struct Derived
   : Base
{
};

Derived source_Derived();

Derived d;
d.destructive_read(source_Derived());

I want to distructively extract information from the Base part of a
temporary Derived after binding it to a Base&.

One of my problems with the proposed "implicit conversion/ binding
temporary" rule is that it puts the question of "can a temporary bind
to a reference" in the hands of the client code.  I believe that the
only one who can decide if it is safe to bind a temporary to a
reference is the author of the method accepting (or not) the temporary.

If the design of the method is to output information through the
referenced argument, then a temporary should not be allowed to bind to
it.  If the design of the method is to destructively extract
information from the argument, then a temporary should be allowed to
bind.  Only the method designer can know these things.

--
Howard Hinnant

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 17 Jul 2001 22:47:14 GMT
Raw View
hinnant@antispam.twcny.rr.com (Howard Hinnant) wrote (abridged):
> One of my problems with the proposed "implicit conversion/ binding
> temporary" rule is that it puts the question of "can a temporary bind
> to a reference" in the hands of the client code.  I believe that the
> only one who can decide if it is safe to bind a temporary to a
> reference is the author of the method accepting (or not) the temporary.

I disagree. I see an analogy with the function return value. The author of
the function makes it available, but the client decides whether to use it
or not. If we can ignore return values we should be able to ignore "out"
parameters too. The decision belongs in the client code.

Even if the author thinks it is not safe, the most she can do is force the
client to bind a named variable. That doesn't guarantee that the client
will inspect its value.


> I'm concerned about this case: [...]
>
> d.destructive_read(source_Derived());

Agreed. Although this involves a derived-to-base implicit conversion, it
doesn't seem unsafe. The reason is that the temporary already existed; it
was created by source_Derived(), not by the implicit conversion.

I hope we can find some legalese which nails down exactly when conversions
are allowed. We want to disallow only implicit conversions which create
new objects.


[From an earlier article]
> How does it matter how the temporary was created?

The dangerous cases are those where we don't realise a temporary is
involved. If the temporary was created explicitly, then we can presume the
programmer knew what she was doing.

Implicit conversions, however, can be very difficult to spot. All of the
strong anti-binding examples I've seen have involved implicit conversions.
It makes sense to seek a rule which forbids the dangerous cases while
admitting the safe and useful ones.


> The logic of not binding a reference to a temporary follows from:  a
> reference argument is used for outputting information (and maybe
> inputting as well).  If you don't want to output information via an
> argument, then that argument should be const.  And if the argument is a
> temporary, then by definition it can not be used to output information.
> Therefore temporaries should not bind to non-const referenece.
>
> However this logic fails ...

Agreed; I don't think the logic is good, for the reasons I gave above.
There are valid reasons for ignoring the value of an out-parameter.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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.research.att.com/~austern/csc/faq.html                ]