Topic: The temporary&reference problem, revisited.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 29 Jan 2016 10:02:54 -0800 (PST)
Raw View
------=_Part_804_1956305018.1454090574912
Content-Type: multipart/alternative;
boundary="----=_Part_805_1464348014.1454090574913"
------=_Part_805_1464348014.1454090574913
Content-Type: text/plain; charset=UTF-8
For the purposes of this post, I define the "temporary&reference problem"
to mean dealing with the many variations of this problem:
auto sv = string_view("foo"s + tostring(someNumber));
This creates a view, but it is a view into a temporary. One that will be
destroyed immediately after creating the string_view.
There have been a number of attempts at resolving this problem. P0066's
solution, Generalized Lifetime Extension <http://wg21.link/P0066>, was
effectively a way to ensure that any temporaries used to build a value
would remain in existence so long as the value does. It also handled things
like returning references to parts of temporaries and the like. The goal of
this solution is to make the above code work.
It was also apparently rejected at Kona
<https://botondballo.wordpress.com/2015/11/09/trip-report-c-standards-meeting-in-kona-october-2015/>
..
A less-world-changing approach to solving this problem is to just make the
runtime error a compile-time error. And indeed, `gsl::string_span` does
exactly that.
But this also prevents this:
void func(string_span sp);
func(string_span("foo"s + tostring(someNumber)));
By the rules of C++ temporaries, this could ought to execute. But
`string_span` disallows it. In trying to prevent problem #1, it *creates*
problem #2. Right now, the C++ language has no way to forbid #1 without
also forbidding #2.
I propose that it *could*.
There is one big difference between case #1 and case #2. In case #1, we are
initializing a variable. In case #2, we are initializing a *parameter*
(Yes, I know that's *also* a variable, but bear with me).
So what we need is a way to designate that a particular constructor can
only legally be called to initialize temporaries or parameters. If the
constructor is called to initialize *any other* kind of object (return
values, `new` calls, non-parameter variables), then the program is
ill-formed.
Note that, thanks to P0135 (Guaranteed Elision), we don't have to worry
about `auto sv = string_view(...)` technically being an initialization of a
temporary, followed by copying/moving that temporary into a variable. By
P0135's rules, that is initializing a variable. And therefore would be
disallowed.
Note that this will not solve every temporary problem. For example, while
P0135 saves us from case #1, it does nothing about this:
string_span modifier(string_span sp) {return string_span(sp.begin() + 2, sp.
end());}
auto sv = modifier(string_span("foo"s + tostring(someNumber)));
This is unfortunate. But our goal here is not like P0066, which requires
annotating the whole world. There will always be cases that can slip
through. The goal here is just to make the most common cases viable, while
disallowing the most common mistakes.
At the very least, the fact that `auto sv = string_span(...)` would fail is
a good clue that sticking `modifier` between them is a bad idea. Also, it
would make it a *lot* easier on static analysis tools if they know right
away that a particular function parameter is initialized through a
"temporary constructor", which implicitly means that the object is a
reference to a temporary. This syntax would allow SA tools to see that and
make it easier for them to see the problem with the `modifier` example.
The minimum syntax would be some form of context-sensitive keyword, used
after the declaration and definition of a constructor. It would not
participate in overload resolution, so either a constructor is a temporary
one, or it is not. Much the same way that `explicit` works now.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_805_1464348014.1454090574913
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">For the purposes of this post, I define the "temporar=
y&reference problem" to mean dealing with the many variations of t=
his problem:<br><br><div class=3D"prettyprint" style=3D"background-color: r=
gb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; b=
order-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div =
class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"> sv </span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> string_vie=
w</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><=
span style=3D"color: #080;" class=3D"styled-by-prettify">"foo"</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify">s </span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">+</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> tostring</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">someNumber</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">));</span></div></code></div><br>This=
creates a view, but it is a view into a temporary. One that will be destro=
yed immediately after creating the string_view.<br><br>There have been a nu=
mber of attempts at resolving this problem. <a href=3D"http://wg21.link/P00=
66">P0066's solution, Generalized Lifetime Extension</a>, was effective=
ly a way to ensure that any temporaries used to build a value would remain =
in existence so long as the value does. It also handled things like returni=
ng references to parts of temporaries and the like. The goal of this soluti=
on is to make the above code work.<br><br>It was also apparently <a href=3D=
"https://botondballo.wordpress.com/2015/11/09/trip-report-c-standards-meeti=
ng-in-kona-october-2015/">rejected at Kona</a>.<br><br>A less-world-changin=
g approach to solving this problem is to just make the runtime error a comp=
ile-time error. And indeed, `gsl::string_span` does exactly that.<br><br>Bu=
t this also prevents this:<br><br><div class=3D"prettyprint" style=3D"backg=
round-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-s=
tyle: solid; border-width: 1px; word-wrap: break-word;"><code class=3D"pret=
typrint"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=
=3D"styled-by-prettify">void</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> func</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">string_span sp</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br><br>func</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">string_=
span</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</spa=
n><span style=3D"color: #080;" class=3D"styled-by-prettify">"foo"=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">s </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">+</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> tostring</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">someNumber</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">)));</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span></div></code></div><br>By the ru=
les of C++ temporaries, this could ought to execute. But `string_span` disa=
llows it. In trying to prevent problem #1, it <i>creates</i> problem #2. Ri=
ght now, the C++ language has no way to forbid #1 without also forbidding #=
2.<br><br>I propose that it <i>could</i>.<br><br>There is one big differenc=
e between case #1 and case #2. In case #1, we are initializing a variable. =
In case #2, we are initializing a <i>parameter</i> (Yes, I know that's =
<i>also</i> a variable, but bear with me).<br><br>So what we need is a way =
to designate that a particular constructor can only legally be called to in=
itialize temporaries or parameters. If the constructor is called to initial=
ize <i>any other</i> kind of object (return values, `new` calls, non-parame=
ter variables), then the program is ill-formed.<br><br>Note that, thanks to=
P0135 (Guaranteed Elision), we don't have to=20
worry about `auto sv =3D string_view(...)` technically being an=20
initialization of a temporary, followed by copying/moving that temporary in=
to a variable. By P0135's rules, that is initializing a=20
variable. And therefore would be disallowed.<br><br>Note that this will not=
solve every temporary problem. For example, while P0135 saves us from case=
#1, it does nothing about this:<br><br><div class=3D"prettyprint" style=3D=
"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bo=
rder-style: solid; border-width: 1px; word-wrap: break-word;"><code class=
=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #000;"=
class=3D"styled-by-prettify">string_span modifier</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">string_span sp</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">{</span><span style=3D"color: #008;" class=3D"styled-by-pr=
ettify">return</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> string_span</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">sp<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">begin</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">()</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">+</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #066;" class=3D"style=
d-by-prettify">2</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> sp=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><s=
pan style=3D"color: #008;" class=3D"styled-by-prettify">end</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">());}</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"><br><br></span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> sv </span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">=3D</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> modifier</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">string_span</span><span style=3D"color: #660;" class=3D"styl=
ed-by-prettify">(</span><span style=3D"color: #080;" class=3D"styled-by-pre=
ttify">"foo"</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">s </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">+</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> tost=
ring</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">someNumber</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">)));</span></di=
v></code></div><br>This is unfortunate. But our goal here is not like P0066=
, which requires annotating the whole world. There will always be cases tha=
t can slip through. The goal here is just to make the most common cases via=
ble, while disallowing the most common mistakes.<br><br>At the very least, =
the fact that `auto sv =3D string_span(...)` would fail is a good clue that=
sticking `modifier` between them is a bad idea. Also, it would make it a *=
lot* easier on static analysis tools if they know right away that a particu=
lar function parameter is initialized through a "temporary constructor=
", which implicitly means that the object is a reference to a temporar=
y. This syntax would allow SA tools to see that and make it easier for them=
to see the problem with the `modifier` example.<br><br>The minimum syntax =
would be some form of context-sensitive keyword, used after the declaration=
and definition of a constructor. It would not participate in overload reso=
lution, so either a constructor is a temporary one, or it is not. Much the =
same way that `explicit` works now.<br></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_805_1464348014.1454090574913--
------=_Part_804_1956305018.1454090574912--
.
Author: Matthew Woehlke <mwoehlke.floss@gmail.com>
Date: Fri, 29 Jan 2016 13:24:13 -0500
Raw View
On 2016-01-29 13:02, Nicol Bolas wrote:
> auto sv = string_view("foo"s + tostring(someNumber));
>
> This creates a view, but it is a view into a temporary. One that will be
> destroyed immediately after creating the string_view.
>
> [...]
> A less-world-changing approach to solving this problem is to just make the
> runtime error a compile-time error. And indeed, `gsl::string_span` does
> exactly that.
>
> But this also prevents this:
>
> void func(string_span sp);
>
> func(string_span("foo"s + tostring(someNumber)));
I wonder if that's really an issue (see below).
> By the rules of C++ temporaries, this could ought to execute. But
> `string_span` disallows it. In trying to prevent problem #1, it *creates*
> problem #2. Right now, the C++ language has no way to forbid #1 without
> also forbidding #2.
>
> I propose that it *could*.
>
> [W]hat we need is a way to designate that a particular constructor can
> only legally be called to initialize temporaries or parameters.
What about introducing a form of ctor that may only be used to construct
a temporary? Possible syntax:
class Foo() { Foo(...) &&; };
> Note that this will not solve every temporary problem. For example, while
> P0135 saves us from case #1, it does nothing about this:
>
> string_span modifier(string_span sp) {return string_span(sp.begin() + 2, sp.
> end());}
Isn't that fixable by stating that a must-be-temporary cannot be passed
by value? IOW, require that a must-be-temporary can only be passed to a
function that accepts the same by rvalue-reference.
I guess you still have the problem how to prevent constructing a new
string_span using information in the temporary instance... but as you
mentioned (snipped), that's starting to become a *much* more obvious (to
the programmer and to SA tools) problem. (The down side, of course, is
possibly requiring a lot more overloads taking rvalue-references.)
> The minimum syntax would be some form of context-sensitive keyword, used
> after the declaration and definition of a constructor. It would not
> participate in overload resolution, so either a constructor is a temporary
> one, or it is not. Much the same way that `explicit` works now.
I nominate '&&' for that "keyword" :-).
--
Matthew
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-proposals/.
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Fri, 29 Jan 2016 11:08:08 -0800 (PST)
Raw View
------=_Part_1593_227666761.1454094489046
Content-Type: multipart/alternative;
boundary="----=_Part_1594_106643764.1454094489047"
------=_Part_1594_106643764.1454094489047
Content-Type: text/plain; charset=UTF-8
On Friday, January 29, 2016 at 1:24:34 PM UTC-5, Matthew Woehlke wrote:
>
> On 2016-01-29 13:02, Nicol Bolas wrote:
> > Note that this will not solve every temporary problem. For example,
> while
> > P0135 saves us from case #1, it does nothing about this:
> >
> > string_span modifier(string_span sp) {return string_span(sp.begin() + 2,
> sp.
> > end());}
>
> Isn't that fixable by stating that a must-be-temporary cannot be passed
> by value? IOW, require that a must-be-temporary can only be passed to a
> function that accepts the same by rvalue-reference.
>
So you force the user of Case #2 to write two overloads: one that takes
non-temporaries and one that takes temporaries. That's a lot of code
duplication.
Remember: the goal is to allow Case #1 to fail (initializing a variable)
while allowing case #2 to succeed (initializing a parameter). The function
being called shouldn't need to be changed to accommodate what you're doing.
And it *certainly* shouldn't cause the function to need a separate overload
to handle non-temporaries.
This is the point of having constructors annotated in this way being able
to initialize function parameters as well as temporaries.
I guess you still have the problem how to prevent constructing a new
> string_span using information in the temporary instance... but as you
> mentioned (snipped), that's starting to become a *much* more obvious (to
> the programmer and to SA tools) problem. (The down side, of course, is
> possibly requiring a lot more overloads taking rvalue-references.)
>
> > The minimum syntax would be some form of context-sensitive keyword, used
> > after the declaration and definition of a constructor. It would not
> > participate in overload resolution, so either a constructor is a
> temporary
> > one, or it is not. Much the same way that `explicit` works now.
>
> I nominate '&&' for that "keyword" :-).
>
It creates confusion with existing member `&&` syntax. Also, it would
suggest that a `&` version would exist, which it should not.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-proposals/.
------=_Part_1594_106643764.1454094489047
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Friday, January 29, 2016 at 1:24:34 PM UTC-5, Matthew W=
oehlke wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">On 2016-01-29 13:=
02, Nicol Bolas wrote:
<br>> Note that this will not solve every temporary problem. For example=
, while=20
<br>> P0135 saves us from case #1, it does nothing about this:
<br>>=20
<br>> string_span modifier(string_span sp) {return string_span(sp.begin(=
) + 2, sp.
<br>> end());}
<br>
<br>Isn't that fixable by stating that a must-be-temporary cannot be pa=
ssed
<br>by value? IOW, require that a must-be-temporary can only be passed to a
<br>function that accepts the same by rvalue-reference.<br></blockquote><di=
v><br>So you force the user of Case #2 to write two overloads: one that tak=
es non-temporaries and one that takes temporaries. That's a lot of code=
duplication.<br><br>Remember: the goal is to allow Case #1 to fail (initia=
lizing a variable) while allowing case #2 to succeed (initializing a parame=
ter). The function being called shouldn't need to be changed to accommo=
date what you're doing. And it *certainly* shouldn't cause the func=
tion to need a separate overload to handle non-temporaries.<br><br>This is =
the point of having constructors annotated in this way being able to initia=
lize function parameters as well as temporaries.<br><br></div><blockquote c=
lass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px=
#ccc solid;padding-left: 1ex;">
I guess you still have the problem how to prevent constructing a new
<br>string_span using information in the temporary instance... but as you
<br>mentioned (snipped), that's starting to become a *much* more obviou=
s (to
<br>the programmer and to SA tools) problem. (The down side, of course, is
<br>possibly requiring a lot more overloads taking rvalue-references.)
<br>
<br>> The minimum syntax would be some form of context-sensitive keyword=
, used=20
<br>> after the declaration and definition of a constructor. It would no=
t=20
<br>> participate in overload resolution, so either a constructor is a t=
emporary=20
<br>> one, or it is not. Much the same way that `explicit` works now.
<br>
<br>I nominate '&&' for that "keyword" :-).
<br></blockquote><div><br>It creates confusion with existing member `&&=
amp;` syntax. Also, it would suggest that a `&` version would exist, wh=
ich it should not.<br></div></div>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"https://groups.google.com/a/isocpp.org/group=
/std-proposals/">https://groups.google.com/a/isocpp.org/group/std-proposals=
/</a>.<br />
------=_Part_1594_106643764.1454094489047--
------=_Part_1593_227666761.1454094489046--
.