Topic: Core Language Issue: Rvalue References


Author: SG <s.gesemann@gmail.com>
Date: Wed, 13 Oct 2010 11:51:18 CST
Raw View
It seems the rvalue reference update (N2831) was a little too eager
and misses out on optimization opportunities that rvalue references
originally were supposed to foster. I think this post is worthy of a
core language issue.

Before this update we had the following behaviour (N2118):

  int i = 23;

  int &  liref = i; // #1: OK
  int && riref = i; // #2: OK

  double      &  ldref = i; // #3: error
  double const& ldcref = i; // #4: OK, const  ref to temporary
  double     &&  rdref = i; // #5: OK, rvalue ref to temporary

The authors of N2831 found several safety problem cases with rvalue
references and identified a violation of the following principle as
the root cause:

 "Principle of Type-Safe Overloading:
  -----------------------------------
  Every function must be type-safe in isolation,
  without regard to how it has been overloaded."

Basically, the const&/&& overload idiom relies on the const& overload
to attract lvalue objects. Since an rvalue reference was allowed to
refer to an lvalue and the rvalue reference overload is possibly
mutating the object under the assumption that nobody would notice,
this kind of overloading under the old rvalue reference rules was not
type-safe according to the above principle.

The authors of N2831 proposed a new wording to fix the safety problem.
This led to the following behaviour:

  int i = 23;

  int &  liref = i; // #1: OK
  int && riref = i; // #2: error

  double      &  ldref = i; // #3: error
  double const& ldcref = i; // #4: OK, const  ref to temporary
  double     &&  rdref = i; // #5: error

The important change was to make #2 ill-formed. But in addition, the
current wording rules out #5 as well. It specifically only allows an
rvalue reference to be initialized with an rvalue expression. In that
respect an rvalue reference behaves differently compared to an lvalue
reference-to-const. An lvalue-reference-to-const can be initialized
with an expression that leads to a conversion yielding a temporary
object to with the reference is bound. This kind of initialization
should also apply to rvalue references. If we keep the current rules
and rule out #5 we will have unnecessary copying in cases where
lvalues and conversions are involved. For example:

  vector<string> words;
  words.push_back("a string literal");
  words.push_back("is an lvalue");

Since, the current rules don't allow initializations of type #5, the
above code will lead to temporary string objects that are /copied/
into the vector instead of being moved into the vector via the rvalue
reference overload of push_back. There is obviously no harm in
allowing the rvalue reference to bind to this /temporary/ object.

In general, the current rules lead to unnecessary copies when an
lvalue of type T is used as argument to an for a function that is
overloaded on types U const&/U&& where T is not reference-related to U
and only implicitly convertible to a (temporary) object of type U.

I'm proposing to change the wording so that we get the following
behaviour:

  int i = 23;

  int &  liref = i; // #1: OK
  int && riref = i; // #2: error

  double      &  ldref = i; // #3: error
  double const& ldcref = i; // #4: OK, const  ref to temporary
  double     &&  rdref = i; // #5: OK, rvalue ref to temporary

Note: #2 is still disallowed for safety (PTO) reasons. #5 is allowed
because the rvalue reference will be referring to a /temporary/
object.


References:

N2118: Rvalue Reference Proposal (Rev3)
( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html )

N2831: Fixing a Safety Problem with Rvalue References
( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2831.html )


Cheers!
Sebastian

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Dragan Milenkovic <dragan@plusplus.rs>
Date: Thu, 14 Oct 2010 13:37:11 CST
Raw View
On 10/13/2010 07:51 PM, SG wrote:
[snip]

>
> I'm proposing to change the wording so that we get the following
> behaviour:
>
>   int i = 23;
>
>   int&   liref = i; // #1: OK
>   int&&  riref = i; // #2: error
>
>   double&   ldref = i; // #3: error
>   double const&  ldcref = i; // #4: OK, const  ref to temporary
>   double&&   rdref = i; // #5: OK, rvalue ref to temporary
>
> Note: #2 is still disallowed for safety (PTO) reasons. #5 is allowed
> because the rvalue reference will be referring to a /temporary/
> object.
>

IMHO, it sounds fairly legitimate what you are proposing.

I thought for a minute (ignoring legacy limitations) about banning
all implicit conversions that create temporaries when binding
references, leaving the user having to make an explicit temporary
object such as:

  const double & r = double(i);
  double && r = double(i);

This thought came while trying to find an argument for #5 being
an error. To me, if #5 is an error, #4 should also an error
without explicit conversion (and creation of a temporary).

... but I quickly dismissed this idea, and without it I too feel
that #5 should be well formed (as rvalue-references can be
considered to allways bind to temporaries).

--
Dragan

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D <daniel.kruegler@googlemail.c=.om>
Date: Wed, 20 Oct 2010 16:13:28 CST
Raw View
Am 13.10.2010 19:51, schrieb SG:
> It seems the rvalue reference update (N2831) was a little too eager
> and misses out on optimization opportunities that rvalue references
> originally were supposed to foster. I think this post is worthy of a
> core language issue.
>
> Before this update we had the following behaviour (N2118):
>
>    int i = 23;
>
>    int&   liref = i; // #1: OK
>    int&&  riref = i; // #2: OK
>
>    double&   ldref = i; // #3: error
>    double const&  ldcref = i; // #4: OK, const  ref to temporary
>    double&&   rdref = i; // #5: OK, rvalue ref to temporary
>
> The authors of N2831 found several safety problem cases with rvalue
> references and identified a violation of the following principle as
> the root cause:

[..]

> The authors of N2831 proposed a new wording to fix the safety problem.
> This led to the following behaviour:
>
>    int i = 23;
>
>    int&   liref = i; // #1: OK
>    int&&  riref = i; // #2: error
>
>    double&   ldref = i; // #3: error
>    double const&  ldcref = i; // #4: OK, const  ref to temporary
>    double&&   rdref = i; // #5: error
>
> The important change was to make #2 ill-formed. But in addition, the
> current wording rules out #5 as well.

[..]

> Since, the current rules don't allow initializations of type #5, the
> above code will lead to temporary string objects that are /copied/
> into the vector instead of being moved into the vector via the rvalue
> reference overload of push_back. There is obviously no harm in
> allowing the rvalue reference to bind to this /temporary/ object.
>
> In general, the current rules lead to unnecessary copies when an
> lvalue of type T is used as argument to an for a function that is
> overloaded on types U const&/U&&  where T is not reference-related to U
> and only implicitly convertible to a (temporary) object of type U.
>
> I'm proposing to change the wording so that we get the following
> behaviour:
>
>    int i = 23;
>
>    int&   liref = i; // #1: OK
>    int&&  riref = i; // #2: error
>
>    double&   ldref = i; // #3: error
>    double const&  ldcref = i; // #4: OK, const  ref to temporary
>    double&&   rdref = i; // #5: OK, rvalue ref to temporary
>
> Note: #2 is still disallowed for safety (PTO) reasons. #5 is allowed
> because the rvalue reference will be referring to a /temporary/
> object.

Note that the currently proposed resolution of
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1138

(which was opened in response to the NB comments DE 10, GB 37, and
US 48) does allow for this initialization.

HTH & Greetings from Bremen,

Daniel Kr=FCgler

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu <std-c%2B%2B@netlab.cs.rpi.edu>]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]