Topic: (N2118)Rvalue reference may create a loophole in the type system


Author: pongba@gmail.com
Date: Wed, 18 Jul 2007 22:44:05 CST
Raw View
In particular I'm considering the following code:

int&& i = 0;
i++;

this actually compiles(because a named rvalue reference is treated as
a lvalue for safety reasons(e.g. moved more than once)), which is very
bothersome, because the whole point of the current wording that
forbids non-const reference to bind to rvalue is to prevent users from
modifying a rvalue through a reference.

Now this safe-net is broken.

IMO the wording(N2118) should be strengthened, so that for build
operators, rvalue references are treated as rvalue, thus preventing i+
+ from compiling.

---
[ 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: "Bronek Kozicki" <brok@spam-trap-cop.net>
Date: Thu, 19 Jul 2007 08:25:35 CST
Raw View
pongba@gmail.com wrote:
> In particular I'm considering the following code:
>
> int&& i = 0;
> i++;
>
> this actually compiles(because a named rvalue reference is treated as
> a lvalue for safety reasons(e.g. moved more than once)), which is very
> bothersome,

or is it not? You just incremented a *temporary* created from a literal,
and this temporary value is not const (and lives long enough to be
safely accessed in the second line). Also, you used rvalue-reference and
not plain reference, thus the intent is quite visible in the code.
Anything wrong with it?


B.


---
[ 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: dave@boost-consulting.com (David Abrahams)
Date: Thu, 19 Jul 2007 15:24:50 GMT
Raw View
on Thu Jul 19 2007, pongba-AT-gmail.com wrote:

> In particular I'm considering the following code:
>
> int&& i = 0;
> i++;
>
> this actually compiles(because a named rvalue reference is treated as
> a lvalue for safety reasons(e.g. moved more than once)), which is very
> bothersome, because the whole point of the current wording that
> forbids non-const reference to bind to rvalue is to prevent users from
> modifying a rvalue through a reference.

rvalue references provide a way to _explicitly_ circumvent that rule.
That's a major feature, without which rvalue references would be
useless.

One might consider prohibiting auto ("on the stack") rvalue
references, though.  I'm not sure whether they're useful.  Howard?

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

The Astoria Seminar ==> http://www.astoriaseminar.com

---
[ 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: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: Thu, 19 Jul 2007 14:56:20 CST
Raw View
David Abrahams skrev:
> on Thu Jul 19 2007, pongba-AT-gmail.com wrote:
>
>> In particular I'm considering the following code:
>>
>> int&& i = 0;
>> i++;
>>
>> this actually compiles

Why is that surprising? Do you also find

vector<int> get_vector();
vector<int>&& v = get_vector();

surprising?

> rvalue references provide a way to _explicitly_ circumvent that rule.
> That's a major feature, without which rvalue references would be
> useless.
>
> One might consider prohibiting auto ("on the stack") rvalue
> references, though.  I'm not sure whether they're useful.  Howard?

It would be bad to prohibit that IMO. For example, the new for-loop uses it:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2243.html#the-range-based-for-statement

-Thorsten

---
[ 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: pongba@gmail.com
Date: Fri, 20 Jul 2007 01:59:27 CST
Raw View
On Jul 20, 4:56 am, Thorsten Ottosen <thorsten.otto...@dezide.com>
wrote:
> David Abrahams skrev:
>
> > on Thu Jul 19 2007, pongba-AT-gmail.com wrote:
>
> >> In particular I'm considering the following code:
>
> >> int&& i = 0;
> >> i++;
>
> >> this actually compiles
>
> Why is that surprising? Do you also find
>
> vector<int> get_vector();
> vector<int>&& v = get_vector();
>
> surprising?
>
> > rvalue references provide a way to _explicitly_ circumvent that rule.
> > That's a major feature, without which rvalue references would be
> > useless.
>
> > One might consider prohibiting auto ("on the stack") rvalue
> > references, though.  I'm not sure whether they're useful.  Howard?

Aren't they on the stack anyway? I mean, even when I'm writing a move
constructor, the rvalue reference parameter is on the stack.

> It would be bad to prohibit that IMO. For example, the new for-loop uses it:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2243.html#th...
>

Good Point!

---
[ 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: pongba@gmail.com
Date: Fri, 20 Jul 2007 08:21:24 CST
Raw View
On Jul 19, 11:24 pm, d...@boost-consulting.com (David Abrahams) wrote:
> on Thu Jul 19 2007, pongba-AT-gmail.com wrote:
>
> > In particular I'm considering the following code:
>
> > int&& i = 0;
> > i++;
>
> > this actually compiles(because a named rvalue reference is treated as
> > a lvalue for safety reasons(e.g. moved more than once)), which is very
> > bothersome, because the whole point of the current wording that
> > forbids non-const reference to bind to rvalue is to prevent users from
> > modifying a rvalue through a reference.
>
> rvalue references provide a way to _explicitly_ circumvent that rule.
> That's a major feature, without which rvalue references would be
> useless.

How about:

double d = 0;
int&& r = d;
r++; // a *temporary* is incremented, which has nothing to do with d

Isn't this surprising? I mean, given that the current rule prevent
this from happening through only allowing a const reference to bind to
a rvalue.


---
[ 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: dave@boost-consulting.com (David Abrahams)
Date: Fri, 20 Jul 2007 15:47:06 GMT
Raw View
on Fri Jul 20 2007, pongba-AT-gmail.com wrote:

>
> How about:
>
> double d = 0;
> int&& r = d;
> r++; // a *temporary* is incremented, which has nothing to do with d

Huh?

> Isn't this surprising?

Your comment is surprising.  What makes you think a temporary is
incremented, and d isn't incremented, here?

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

The Astoria Seminar ==> http://www.astoriaseminar.com

---
[ 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: dave@boost-consulting.com (David Abrahams)
Date: Fri, 20 Jul 2007 15:47:45 GMT
Raw View
on Fri Jul 20 2007, pongba-AT-gmail.com wrote:

>> > rvalue references provide a way to _explicitly_ circumvent that rule.
>> > That's a major feature, without which rvalue references would be
>> > useless.
>>
>> > One might consider prohibiting auto ("on the stack") rvalue
>> > references, though.  I'm not sure whether they're useful.  Howard?
>
> Aren't they on the stack anyway? I mean, even when I'm writing a move
> constructor, the rvalue reference parameter is on the stack.

That's why I put it in quotes.  I meant only to include rvalue
references that are (implicitly) declared auto (the old meaning of
auto).

And, FWIW, I didn't mean to include rvalue references that use the new
meaning of auto.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

The Astoria Seminar ==> http://www.astoriaseminar.com

---
[ 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: jam <farid.mehrabi@gmail.com>
Date: Fri, 20 Jul 2007 11:08:53 CST
Raw View
On Jul 20, 5:21 pm, pon...@gmail.com wrote:
> On Jul 19, 11:24 pm, d...@boost-consulting.com (David Abrahams) wrote:
>
>
>
>
>
> > on Thu Jul 19 2007, pongba-AT-gmail.com wrote:
>
> > > In particular I'm considering the following code:
>
> > > int&& i = 0;
> > > i++;
>
> > > this actually compiles(because a named rvalue reference is treated as
> > > a lvalue for safety reasons(e.g. moved more than once)), which is very
> > > bothersome, because the whole point of the current wording that
> > > forbids non-const reference to bind to rvalue is to prevent users from
> > > modifying a rvalue through a reference.
>
> > rvalue references provide a way to _explicitly_ circumvent that rule.
> > That's a major feature, without which rvalue references would be
> > useless.
>
> How about:
>
> double d = 0;
> int&& r = d;
> r++; // a *temporary* is incremented, which has nothing to do with d
>
> Isn't this surprising? I mean, given that the current rule prevent
> this from happening through only allowing a const reference to bind to
> a rvalue.
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-...@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html                     ]- Hide quoted text -
>
> - Show quoted text -

In order to prevent this ,could built-in casting operators for
intrinsic types be interpreted as const operators (e.g operator const
int(const double&) )??

regards,
FM.

---
[ 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: pongba@gmail.com
Date: Sat, 21 Jul 2007 00:45:12 CST
Raw View
On Jul 20, 11:47 pm, d...@boost-consulting.com (David Abrahams) wrote:
> on Fri Jul 20 2007, pongba-AT-gmail.com wrote:
>
>
>
> > How about:
>
> > double d = 0;
> > int&& r = d;
> > r++; // a *temporary* is incremented, which has nothing to do with d
>
> Huh?
>
> > Isn't this surprising?
>
> Your comment is surprising.  What makes you think a temporary is
> incremented, and d isn't incremented, here?

Well, the output of my code under the conceptgcc-boostcon edition is
my first clue.

Second, since d isn't reference-compatible with r, r is supposed to be
bound to a temporary created by copy initialization from d, according
to N2118:

8.5.3
Otherwise, a temporary of type ``cv1 T1" is created and initialized
from the initializer expression using the rules for a non-reference
copy initialization (dcl.init). The reference is then bound to the
temporary.

---
[ 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: Mathias Gaunard <loufoque@gmail.com>
Date: Sat, 21 Jul 2007 04:53:52 CST
Raw View
On Jul 20, 5:47 pm, d...@boost-consulting.com (David Abrahams) wrote:

> > double d = 0;
> > int&& r = d;
> > r++; // a *temporary* is incremented, which has nothing to do with d

> Your comment is surprising.  What makes you think a temporary is
> incremented, and d isn't incremented, here?

Because double isn't int.
The double is converted to an int, hence introducing a temporary.

---
[ 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: David Abrahams <dave@boost-consulting.com>
Date: Sun, 22 Jul 2007 13:16:39 CST
Raw View
on Sat Jul 21 2007, Mathias Gaunard <loufoque-AT-gmail.com> wrote:

> On Jul 20, 5:47 pm, d...@boost-consulting.com (David Abrahams) wrote:
>
>> > double d = 0;
>> > int&& r = d;
>> > r++; // a *temporary* is incremented, which has nothing to do with d
>
>> Your comment is surprising.  What makes you think a temporary is
>> incremented, and d isn't incremented, here?
>
> Because double isn't int.

Ohhhh...  I missed that part, which I guess is the whole point.

> The double is converted to an int, hence introducing a temporary.

Right.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

The Astoria Seminar ==> http://www.astoriaseminar.com

---
[ 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: "Bronek Kozicki" <brok@spam-trap-cop.net>
Date: Sun, 22 Jul 2007 13:16:08 CST
Raw View
jam <farid.mehrabi@gmail.com> wrote:
> In order to prevent this ,could built-in casting operators for
> intrinsic types be interpreted as const operators (e.g operator const
> int(const double&) )??

and what would that limitation buy us? I find it quite natural that
temporary copy can be operated upon independly of its source value.


B.

---
[ 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: fishcorn@gmail.com (John Moeller)
Date: Sun, 22 Jul 2007 18:16:03 GMT
Raw View
pongba@gmail.com wrote:
> On Jul 20, 11:47 pm, d...@boost-consulting.com (David Abrahams) wrote:
>> on Fri Jul 20 2007, pongba-AT-gmail.com wrote:
>>
>>
>>
>>> How about:
>>> double d = 0;
>>> int&& r = d;
>>> r++; // a *temporary* is incremented, which has nothing to do with d
>> Huh?
>>
>>> Isn't this surprising?
>> Your comment is surprising.  What makes you think a temporary is
>> incremented, and d isn't incremented, here?
>
> Well, the output of my code under the conceptgcc-boostcon edition is
> my first clue.
>
> Second, since d isn't reference-compatible with r, r is supposed to be
> bound to a temporary created by copy initialization from d, according
> to N2118:
>
> 8.5.3
> Otherwise, a temporary of type ``cv1 T1" is created and initialized
> from the initializer expression using the rules for a non-reference
> copy initialization (dcl.init). The reference is then bound to the
> temporary.

Regardless, I can't say that I'm surprised by your code.  You're
grabbing a non-const rvalue (because you assigned it to a non-const
rvalue reference), and you're performing a non-const operation on it.
In the code, you're stating exactly what you want to do (convert a
double to an int and increment the result), and it does it.  I don't
really understand where the surprise is.  What if you were to do this:

double d = 0.0;
int r = d;
r++;

Would you be surprised at the result?

Can you explain where the concern about type-safety is?  Maybe we need
an example with classes instead of primitives?

--

John Moeller
fishcorn@gmail.com

---
[ 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: jam <farid.mehrabi@gmail.com>
Date: Wed, 25 Jul 2007 09:52:28 CST
Raw View
On Jul 22, 10:16 pm, "Bronek Kozicki" <b...@spam-trap-cop.net> wrote:
> jam <farid.mehr...@gmail.com> wrote:
> > In order to prevent this ,could built-in casting operators for
> > intrinsic types be interpreted as const operators (e.g operator const
> > int(const double&) )??

I felt great regret after that post of mine(this happens often).

> and what would that limitation buy us? I find it quite natural that
> temporary copy can be operated upon independly of its source value.

right.

regards,
FM

---
[ 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: jcoffin@taeus.com (Jerry Coffin)
Date: Wed, 25 Jul 2007 23:10:16 GMT
Raw View
In article <1184911584.328516.62110@g12g2000prg.googlegroups.com>,
pongba@gmail.com says...

[ ... ]

> How about:
>
> double d = 0;
> int&& r = d;
> r++; // a *temporary* is incremented, which has nothing to do with d
>
> Isn't this surprising? I mean, given that the current rule prevent
> this from happening through only allowing a const reference to bind to
> a rvalue.

If you really want 'r' to be an rvalue reference to the same type as
'd', shouldn't you really use auto (in its new meaning) to express that
intent directly?

--
    Later,
    Jerry.

The universe is a figment of its own imagination.

---
[ 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: frege <gottlobfrege@gmail.com>
Date: Thu, 26 Jul 2007 00:00:29 CST
Raw View
On Jul 25, 7:10 pm, jcof...@taeus.com (Jerry Coffin) wrote:
>
> If you really want 'r' to be an rvalue reference to the same type as
> 'd', shouldn't you really use auto (in its new meaning) to express that
> intent directly?
>


Speaking of auto and rvalue refs, I've been meaning to ask (to Howard
mostly, based on a slide from the BoostCon)...

void f(int i)
{
}
void f(int const & cr)
{
}
void f(int && r)
{
   auto q = r;
   decltype(r) s = r;
   f(r);
   f(q);
   f(s);
   f(std::move(r));
   //etc
}

what are the types of q and s?  which f is called in each case?

what about

template <typename T>
void f(T t)
{
   auto q = t;
   decltype(t) s = t;
   //...
}

for most types T, I suspect q and s are of type T, but I'm not so sure
when T is a &&.

so are these 3 functions different:

template <typename T>
void f1(T t)
{
   f(t);
}

template <typename T>
void f2(T t)
{
   auto q = t;
   f(q);
}

template <typename T>
void f2(T t)
{
   decltype(t) q = t;
   f(q);
}

I'd like to think that the creation of a temporary doesn't (typically
- ie for regular types) change anything, but does it when T is an
rvalue ref?

Tony

---
[ 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: howard.hinnant@gmail.com (Howard Hinnant)
Date: Thu, 26 Jul 2007 21:02:59 GMT
Raw View
In article <1185425242.169428.219920@i38g2000prf.googlegroups.com>,
 frege <gottlobfrege@gmail.com> wrote:

> On Jul 25, 7:10 pm, jcof...@taeus.com (Jerry Coffin) wrote:
> >
> > If you really want 'r' to be an rvalue reference to the same type as
> > 'd', shouldn't you really use auto (in its new meaning) to express that
> > intent directly?
> >
>
>
> Speaking of auto and rvalue refs, I've been meaning to ask (to Howard
> mostly, based on a slide from the BoostCon)...
>
> void f(int i)
> {
> }
> void f(int const & cr)
> {
> }
> void f(int && r)
> {
>    auto q = r;
>    decltype(r) s = r;
>    f(r);
>    f(q);
>    f(s);
>    f(std::move(r));
>    //etc
> }
>
> what are the types of q and s?  which f is called in each case?

Partial answer:

f(int) and f(int const &) are ambiguous (under C++03 and C++0X).

I don't know what auto does (haven't kept up with it, and I don't
believe it is in the draft yet).

Otherwise, every use of r, q, and s inside of f() will be treated as an
lvalue, not as an rvalue.  There's only two places where named variables
will be treated as rvalues:  both of those places are where copy elision
is already legal today.

1.  Returning a local auto-storage variable by value.
2.  Throwing a local auto-storage variable.

> what about
>
> template <typename T>
> void f(T t)
> {
>    auto q = t;
>    decltype(t) s = t;
>    //...
> }
>
> for most types T, I suspect q and s are of type T, but I'm not so sure
> when T is a &&.

By today's rules, if you:

void g()
{
   int i = 0;
   int& ir = i;
   f(ir);
}

T is deduced as int, not int&.  Same answer if you change ir:

int&& ir = i;

Summary:  There are only a few places where && behaves differently from
&.  If in doubt, assume that && behaves the same as &, and you'll be
correct more often than not.

>
> so are these 3 functions different:
>
> template <typename T>
> void f1(T t)
> {
>    f(t);
> }
>
> template <typename T>
> void f2(T t)
> {
>    auto q = t;
>    f(q);
> }
>
> template <typename T>
> void f2(T t)
> {
>    decltype(t) q = t;
>    f(q);
> }
>
> I'd like to think that the creation of a temporary doesn't (typically
> - ie for regular types) change anything, but does it when T is an
> rvalue ref?

All of those should behave identically, treating t and q as lvalues.

If you have a name for it (a variable name), it is an lvalue.  It will
prefer lvalue references in overload resolution.

If you don't have a name for it (such as the return value of a
function), then it is an rvalue ... with one exception: unnamed lvalue
references are lvalues.

A& an_lvalue();
A&& an_rvalue();
A another_rvalue();

char source(const A&);
int  source(A&&);

int main()
{
    A a;
    an_lvalue() = a;  // ok
    an_rvalue() = a;  // compile time error
    another_rvalue() = a;  // compile time error
    A&& ar = a;  // ar is an lvalue, it has a name "ar"
    ar = a;  // ok
    char c1 = source(ar);  // returns char, not int
    char c2 = source(an_lvalue());  // returns char
    int i1  = source(an_rvalue());  // returns int
}

-Howard

---
[ 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                      ]