Topic: Destructive move, via forwarding and
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sun, 20 Jan 2019 09:24:05 -0800 (PST)
Raw View
------=_Part_1484_1843130595.1548005045816
Content-Type: multipart/alternative;
boundary="----=_Part_1485_61470356.1548005045816"
------=_Part_1485_61470356.1548005045816
Content-Type: text/plain; charset="UTF-8"
On Sunday, January 20, 2019 at 8:29:17 AM UTC-5, dcrc...@gmail.com wrote:
>
> - A new kind of reference, an "owning reference".
>
Let me stop you right there: No.
C++ needs a new kind of reference like it needs a hole in the head. However
useful the feature may be, it's *never* going to be good enough to be worth
that level of pain.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ca96ebeb-8c6a-4dc3-a703-28a37feff900%40isocpp.org.
------=_Part_1485_61470356.1548005045816
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Sunday, January 20, 2019 at 8:29:17 AM UTC-5, dcrc...@g=
mail.com wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-=
left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr=
"><div>- A new kind of reference, an "owning reference".</div></d=
iv></blockquote><div><br></div><div>Let me stop you right there: No.</div><=
div><br></div><div>C++ needs a new kind of reference like it needs a hole i=
n the head. However useful the feature may be, it's <i>never</i> going =
to be good enough to be worth that level of pain.<br></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ca96ebeb-8c6a-4dc3-a703-28a37feff900%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ca96ebeb-8c6a-4dc3-a703-28a37feff900=
%40isocpp.org</a>.<br />
------=_Part_1485_61470356.1548005045816--
------=_Part_1484_1843130595.1548005045816--
.
Author: Tony V E <tvaneerd@gmail.com>
Date: Sun, 20 Jan 2019 17:26:50 -0500
Raw View
<html><head></head><body lang=3D"en-US" style=3D"background-color: rgb(255,=
255, 255); line-height: initial;"> =
<div style=3D"width: 100%; fo=
nt-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif=
; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, =
255, 255);">Dangling references and destructive move are two things that co=
uld possibly be solved by something called 'owning references'.</div><div s=
tyle=3D"width: 100%; font-size: initial; font-family: Calibri, 'Slate Pro',=
sans-serif, sans-serif; color: rgb(31, 73, 125); text-align: initial; back=
ground-color: rgb(255, 255, 255);"><br></div><div style=3D"width: 100%; fon=
t-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-serif;=
color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255, 2=
55, 255);">I haven't read the paper, but the high cost of another reference=
could be worth it if it solved these issues.</div><div style=3D"width: 100=
%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-=
serif; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(=
255, 255, 255);"><br></div><div style=3D"width: 100%; font-size: initial; f=
ont-family: Calibri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73=
, 125); text-align: initial; background-color: rgb(255, 255, 255);">The hig=
her cost is an alternative language (like Rust).</div><div style=3D"width: =
100%; font-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sa=
ns-serif; color: rgb(31, 73, 125); text-align: initial; background-color: r=
gb(255, 255, 255);"><br></div> =
=
<div style=3D"width: 100%; font-size: initial; font-family: Ca=
libri, 'Slate Pro', sans-serif, sans-serif; color: rgb(31, 73, 125); text-a=
lign: initial; background-color: rgb(255, 255, 255);"><br style=3D"display:=
initial"></div> =
=
<div style=3D"f=
ont-size: initial; font-family: Calibri, 'Slate Pro', sans-serif, sans-seri=
f; color: rgb(31, 73, 125); text-align: initial; background-color: rgb(255,=
255, 255);">Sent from my BlackBerry portable Babb=
age Device</div> =
=
<table width=3D"100%" styl=
e=3D"background-color:white;border-spacing:0px;"> <tbody><tr><td colspan=3D=
"2" style=3D"font-size: initial; text-align: initial; background-color: rgb=
(255, 255, 255);"> <div style=3D"border-style: so=
lid none none; border-top-color: rgb(181, 196, 223); border-top-width: 1pt;=
padding: 3pt 0in 0in; font-family: Tahoma, 'BB Alpha Sans', 'Slate Pro'; f=
ont-size: 10pt;"> <div><b>From: </b>Nicol Bolas</div><div><b>Sent: </b>Sun=
day, January 20, 2019 12:24 PM</div><div><b>To: </b>ISO C++ Standard - Futu=
re Proposals</div><div><b>Reply To: </b>std-proposals@isocpp.org</div><div>=
<b>Cc: </b>dcrc2cpp@gmail.com</div><div><b>Subject: </b>[std-proposals] Re:=
Destructive move, via forwarding and destructuring operations</div></div><=
/td></tr></tbody></table><div style=3D"border-style: solid none none; borde=
r-top-color: rgb(186, 188, 209); border-top-width: 1pt; font-size: initial;=
text-align: initial; background-color: rgb(255, 255, 255);"></div><br><div=
id=3D"_originalContent" style=3D""><div dir=3D"ltr">On Sunday, January 20,=
2019 at 8:29:17 AM UTC-5, dcrc...@gmail.com wrote:<blockquote class=3D"gma=
il_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid=
;padding-left: 1ex;"><div dir=3D"ltr"><div>- A new kind of reference, an "o=
wning reference".</div></div></blockquote><div><br></div><div>Let me stop y=
ou right there: No.</div><div><br></div><div>C++ needs a new kind of refere=
nce like it needs a hole in the head. However useful the feature may be, it=
's <i>never</i> going to be good enough to be worth that level of pain.<br>=
</div></div>
<p></p>
-- <br>
You received this message because you are subscribed to the Google Groups "=
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>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ca96ebeb-8c6a-4dc3-a703-28a37feff900%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.goo=
gle.com/a/isocpp.org/d/msgid/std-proposals/ca96ebeb-8c6a-4dc3-a703-28a37fef=
f900%40isocpp.org</a>.<br>
<br><!--end of _originalContent --></div></body></html>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/20190120222650.5222481.91670.69069%40=
gmail.com?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.com=
/a/isocpp.org/d/msgid/std-proposals/20190120222650.5222481.91670.69069%40gm=
ail.com</a>.<br />
.
Author: David Collier <dcrc2cpp@gmail.com>
Date: Mon, 21 Jan 2019 13:56:39 +0000
Raw View
--00000000000087b9d4057ff83b4e
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
So this reply reached me by email but Google has deleted it. This seems to
have happened to several messages, including the short reply that I tried
sending a few moments ago. Anyway, some responses inline below:
On Mon, Jan 21, 2019 at 4:11 AM Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> On Sunday, January 20, 2019 at 8:29:17 AM UTC-5, dcrc...@gmail.com wrote:
>>
>> I've written up a version of "destructive move" for C++, attached here.
>> [...] Comments are very welcome; beware that the paper is rather long.
>>
>
> Thanks for mentioning P1144. :)
>
> (1) I think you should find a different word for what you currently call
> "forwarding" and the "forwarding operator" `>>x`, because I don't see the
> connection between what that operator does in your paper and what "perfec=
t
> forwarding" and "forwarding references" do in C++. I guess in a sense th=
e
> `>>` operator is preserving ("forwarding") the value-category of `x`, whi=
ch
> is your new "owning reference" category, similar to how std::forward
> preserves the value-category of lvalue and rvalue references. But your
> operator is specifically *not* a shorthand for std::forward. What
> prevents you from adding a new overload of std::forward?
>
I take your point about naming. The operator *does* do forwarding, but its
more important property is that it ends the lifetime of references, and
ideally the name should reflect that.
Here is why I think it must be an operator and not an ordinary function:
The argument to std::forward is an lvalue reference. If T is a
non-reference type then the signature of std::forward<T> is just
T&& forward(T &);
So for destructive forwarding you might think that the generalization would
be
T~ destructive_forward(T &);
But that doesn't work: when the compiler sees a function taking an lvalue
reference, it doesn't know that the function is going to destroy the
argument. So with that function signature, you'd get a double-destruction
error because the compiler would still call the destructor of the object at
the end of its original scope.
You could change the signature to
T~ destructive_forward(T ~);
and permit the argument to bind to an lvalue (which is not allowed in my
version); but then there would be no visible sign of what's happening at
the call site. That might be OK when the function was specifically named
"forward", but it wouldn't be OK for other random functions which take
owning reference parameters.
> Or in fact, this leads to my next question:
>
> (2) IIUC, you propose that when `x` is declared with `T~ x`, `decltype(x)=
`
> should be `T~`. So is it reasonable to say that `>>x` is just a shorthand
> for `static_cast<decltype(x)>(x)`, in the same way that
> `std::forward<T>(x)` is a shorthand for `static_cast<decltype(x)>(x)`?
> (Caveat: When `decltype(x)` is a non-reference type, `std::forward<T>(x)=
`
> is a shorthand for `static_cast<decltype(x)&&>(x)`. However, your 4.1 say=
s
> that `>>x` is ill-formed when `decltype(x)` is a non-reference type. So I
> think it is correct to say that I could take a program written in your
> style and replace all your `>>`s with `static_cast`s and the program woul=
d
> still do the same thing, is that right?)
>
No: the proposal is that >> is the only way to end the lifetime of a named
reference. Although you *could* give static_cast the same special
treatment, I feel it would be potentially unexpected (see 7.1).
(3) I think your proposal is doomed because of sections 4.2 and 4.3:
>
> > if the forwarding operator is applied to an owning reference, then the
> destructor will no longer be called when the scope of the reference ends.
> We will say that the reference is *live* if the forwarding operator has
> not yet been applied to it; after the operator is applied it is *dead*.
> If an owning reference is still live at the end of its scope, then the
> destructor of the object is invoked. So clearly it is important that the
> compiler must be able to keep track of which references are live.
>
> I think this is a proposal-killer. C++ likes to track things via the
> typesystem, via changes in static type. You're proposing that the compile=
r
> static-analyze the code to track "liveness" without interacting with the
> typesystem at all: a "live" owning ref and a "dead" owning ref are
> completely different beasts as far as the compiler is concerned, but they
> have exactly the same static type. I don't think this will fly at all. C+=
+
> is not Rust.
> To your credit, you know this is a problem and spend a while exploring
> it... but your solution is too complicated to fly.
>
I believe this is an inevitable consequence of wanting to be able to move
from objects with automatic storage duration. For this to work at all, it
*must* be possible for the lifetime of an object to end before the end of
its scope. If you don't have this, you don't have destructive move.
The way I would describe is it that a dead reference doesn't even have a
type. It's not valid to use the name of reference in any way (maybe even
decltype(r) should be forbidden - I can't think of any possible uses for
it).
> (4) I don't understand your example "g1". The "else if" branch is
> commented "OK", and the "else" branch is commented "ERROR", but I don't s=
ee
> any difference between them. Does the curly brace before the final "retur=
n
> -1" actually make a difference? If I wrapped the first two statements of
> the "else if" branch in an extra pair of curly braces, so that "return va=
l"
> was outside those braces, would it stop being "OK" and start being "ERROR=
"?
>
The difference is that execution can continue past the end of the block in
one case but not in the other. I think you're right that I failed to
provide an unambiguous answer to your second question. I actually think you
could define it either way while still being consistent - I have a slight
preference for "no".
(5) The "destructuring" business does seem to be required by your design,
> because otherwise you can't destructively-move from a std::pair (which is
> your core example). But it makes me very uncomfortable. The mental model
> for `pair` is that a pair is just its two members, and that if we destroy
> one member and then destroy the other member, then the pair itself will
> have been completely destroyed and there's no need to call any destructor=
..
> This is 100% true for `pair` =E2=80=94 or true enough. But what about a t=
ype with a
> non-trivial destructor?
>
> struct P {
> int *ptr_;
> P(int *p): ptr_(p) { ptr_->incref(); }
> P(P~ rhs) : ptr_(rhs.ptr_) { ptr_->incref(); } // FOO
> ~P() { ptr_->decref(); }
> };
>
> IIUC, here the parameter `P~ rhs` means that FOO is taking responsibility
> for destroying the object referenced by `rhs`. Your static-analysis stuff
> (which I don't like) makes sure that `rhs`'s destructor gets called at th=
e
> end of the scope because `rhs` was never forwarded-from. So the refcounts
> balance out in this case.
>
> But if we use the destructuring suffix `.*` then that basically counts as
> forwarding-from `rhs`, is that right?
>
> struct P {
> int *ptr_;
> P(int *p): ptr_(p) { ptr_->incref(); }
> P(P~ rhs.*) : ptr_(>>rhs.ptr_) { no_need_to_incref(); } // BAR
> ~P() { ptr_->decref(); }
> };
>
> Here `rhs` will not be destroyed at the end of the scope because it was
> destructured, which counts as forwarding-from. Is that right?
> In this example, if `no_need_to_incref()` throws an exception, then we
> leak a refcount; but that's actually no different from how any constructo=
r
> works, so I think that's okay.
>
Yes, this was exactly my intention.
(6) A big conceptual problem with your destructuring is that it works 100%
> on bases-and-members, which is different from how C++17 structured bindin=
g
> works with a customization point named std::get. (Mind you, C++17
> structured binding is just a messy mistake. I'm not saying you should try
> to be *more* like it.) What this means is that your destructuring will
> not work to forward-out-of a tuple, for example.
>
> void this_will_never_work(std::tuple<T, U>~ tup.*) {
> T t =3D >>std::get<0>(tup); // or whatever
> U u =3D >>std::get<1>(tup);
> }
>
> That's because tuple elements are not stored as (direct) members or
> (direct) bases.
> This also gets back to (5), because you'd have to assume that destroying
> all the members of a tuple somehow destroyed the whole tuple. Unfortunate=
ly
> this is again pretty much true at the machine-code level, but it continue=
s
> to unnerve me at the source-code level.
> The easiest way out is to say that yeah, destructuring doesn't work on
> tuples and you should never destructive-move-out-of a tuple element. P114=
4
> certainly says you should never relocate-out-of a tuple element.
>
This is section 5.7 of my paper. You can move from tuple elements like this=
:
void this_works(std::tuple<T, U>~ tup) {
auto~ [t, u] =3D >>tup;
}
I agree that a named customization point does not work. Maybe this is
unfortunate. Or maybe it makes sense and std::get should really be replaced
with a pure language feature: I agree that C++17 structured bindings are
messy.
(7) IIUC, your proposal does enable almost all the same optimizations that
> P1144 enables. You add a new kind of special member function, which can b=
e
> defaulted, and which (when defaulted) can be analyzed by the compiler to
> find out if it's trivial, and which can be implicitly generated by the
> compiler so source code doesn't need to change. So you do end up with
> struct R { std::unique_ptr<int> m; };
> void foo(std::vector<R>& v) { v.reserve(v.capacity() + 1); }
> producing a memcpy instead of a move-and-destroy-in-a-loop, because the
> compiler implicitly generates `R(R~) =3D default` and verifies that it's
> trivial. This matches your understanding, right?
>
Yes, exactly. It would be really disappointing if this didn't work.
> (8) I say "almost" all because your proposal does not contain any way for
> the user to warrant that their `R(R~)` is trivial when it is *not*
> defaulted.
>
> struct S {
> int i;
> boost::interprocess::offset_ptr<int> p =3D &i; // class invarian=
t:
> p always points to my own i
> S(int i) : i(i) {}
> S(S&& rhs) { i =3D rhs.i; }
> S(S~ rhs) { i =3D rhs.i; }
> ~S() =3D default;
> };
>
> Here, `S`
> - is *actually* trivially destructible;
> - is *conceptually*, but not actually, trivially move-constructible;
> - is *conceptually*, but not actually, trivially relocate-able in your
> terms.
>
> With P1144's proposed attribute, the programmer could ensure that `S`
> - is *actually* trivially destructible;
> - is *conceptually*, but not actually, trivially move-constructible;
> - is *actually* trivially relocatable in P1144's terms.
>
> "What good is being *actually* trivially relocatable, if you can never be
> *actually* trivially move-constructible even in P1144's world?" Well, I'm
> not sure, maybe I'm putting too much weight on this property of P1144. Bu=
t
> "what good is being *actually* trivially relocatable?" =E2=80=94 well, it=
enables
> all these nice memcpy optimizations that we really want to get!
> Being *actually* trivially move-constructible is also perhaps useful, but
> certainly much less frequently. (I can't think of any uses for it off the
> top of my head.)
>
> Of course you could fix this complaint by just adding a warranting
> attribute [[trivially_relocatable]] of your own =E2=80=94 in fact, vendor=
s might do
> it without your needing to propose it. So this is a very minor complaint
> compared to the big ones above and below.
>
OK, I did wonder whether there were any examples like this, and had failed
to think of any. But I agree that you have a valid example here.
(9) I do tend to agree with Nicol that "let's add another kind of
> reference" is probably not going to fly in the real world. I don't think
> it's terribly productive to use that as the *only* reason to shoot this
> proposal down, though. :)
>
> (10) Here are some of the properties of your "owning reference." It binds
> only to "temporary objects" (prvalues). It indicates ownership and
> responsibility for destroying. It is neither an lvalue nor an rvalue
> reference. ...This makes me wonder: Are you *sure* you're not just
> describing a *non-reference, prvalue* type? Thought experiment: Go
> through your examples and eliminate all the `~` sigils. What are you left
> with? I'm not sure, but I optimistically imagine you're left with a
> super-powered version of copy elision, plus the ability to "turn an lvalu=
e
> back into a prvalue" by applying either `>>` or `.*`, plus a sort of
> "prvalue constructor" signature `A(A)` which is legal only if it is
> `=3Ddefault`ed or if the argument is immediately `.*`ed. Okay, this is
> probably crazy. :)
>
I don't think that's crazy. I feel an owning reference is midway between a
reference and a value. I stopped short of making them actual values because=
:
- You can create an owning reference to a type even if it is not
relocatable, which seems important for generic code. I don't think you can
ensure copy elision in enough situations to make this work with just
values. It would be really nice if you could!
- You need some way to declare that a function argument is to be destroyed
by the callee. You could say, we'll pass by value, and annotate the
parameter in some way to say that it will be destroyed by the callee. For
example, annotate the parameter by writing a tilde before the name. But
then what you've got looks just like owning references.
Many thanks for taking the trouble to read through everything, I'm rather
delighted that anyone did!
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAB55TMrQ9oM-3iEn4aekdFVU%3DtRmZO_Kt-6weKydp60zq=
zx3_w%40mail.gmail.com.
--00000000000087b9d4057ff83b4e
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>So this reply reached me by email but Google has dele=
ted it. This seems to have happened to several messages, including the shor=
t reply that I tried sending a few moments ago. Anyway, some responses inli=
ne below:</div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"m_3=
789505939262701249gmail_attr">On Mon, Jan 21, 2019 at 4:11 AM Arthur O'=
Dwyer <<a href=3D"mailto:arthur.j.odwyer@gmail.com" target=3D"_blank">ar=
thur.j.odwyer@gmail.com</a>> wrote:<br></div><blockquote class=3D"gmail_=
quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,=
204);padding-left:1ex"><div dir=3D"ltr">On Sunday, January 20, 2019 at 8:29=
:17 AM UTC-5, <a href=3D"mailto:dcrc...@gmail.com" target=3D"_blank">dcrc..=
..@gmail.com</a> wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0px=
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><di=
v dir=3D"ltr">I've written up a version of "destructive move"=
for C++, attached here. [...] Comments are very welcome; beware that the p=
aper is rather long.</div></blockquote><div><br></div><div>Thanks for menti=
oning P1144. :)</div><div><br></div><div>(1) I think you should find a diff=
erent word for what you currently call "forwarding" and the "=
;forwarding operator" `>>x`, because I don't see the connect=
ion between what that operator does in your paper and what "perfect fo=
rwarding" and "forwarding references" do in C++.=C2=A0 I gue=
ss in a sense the `>>` operator is preserving ("forwarding"=
) the value-category of `x`, which is your new "owning reference"=
category, similar to how std::forward preserves the value-category of lval=
ue and rvalue references. But your operator is specifically <i>not</i> a sh=
orthand for std::forward. What prevents you from adding a new overload of s=
td::forward?</div></div></blockquote><div><br></div><div>I take your point =
about naming. The operator *does* do forwarding, but its more important pro=
perty is that it ends the lifetime of references, and ideally the name shou=
ld reflect that.</div><div><br></div><div>Here is why I think it must be an=
operator and not an ordinary function:</div><div><br></div><div>The argume=
nt to std::forward is an lvalue reference. If T is a non-reference type the=
n the signature of std::forward<T> is just</div><div><br></div><div>T=
&& forward(T &);</div><div><br></div><div>So for destructive fo=
rwarding you might think that the generalization would be</div><div><br></d=
iv><div>T~ destructive_forward(T &);</div><div><br></div><div>But that =
doesn't work: when the compiler sees a function taking an lvalue refere=
nce, it doesn't know that the function is going to destroy the argument=
.. So with that function signature, you'd get a double-destruction error=
because the compiler would still call the destructor of the object at the =
end of its original scope.</div><div><br></div><div>You could change the si=
gnature to</div><div><br></div><div>T~ destructive_forward(T ~);</div><div>=
<br></div><div>and permit the argument to bind to an lvalue (which is not a=
llowed in my version); but then there would be no visible sign of what'=
s happening at the call site. That might be OK when the function was specif=
ically named "forward", but it wouldn't be OK for other rando=
m functions which take owning reference parameters.</div><div>=C2=A0</div><=
blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l=
eft:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div> Or =
in fact, this leads to my next question:</div><div><br></div><div>(2) IIUC,=
you propose that when `x` is declared with `T~ x`, `decltype(x)` should be=
`T~`. So is it reasonable to say that `>>x` is just a shorthand for =
`static_cast<decltype(x)>(x)`, in the same way that `std::forward<=
T>(x)` is a shorthand for `static_cast<decltype(x)>(x)`? =C2=A0(Ca=
veat: When `decltype(x)` is a non-reference type, `std::forward<T>(x)=
` is a shorthand for `static_cast<decltype(x)&&>(x)`. However=
, your 4.1 says that `>>x` is ill-formed when `decltype(x)` is a non-=
reference type. So I think it is correct to say that I could take a program=
written in your style and replace all your `>>`s with `static_cast`s=
and the program would still do the same thing, is that right?)</div></div>=
</blockquote><div><br></div><div>No: the proposal is that >> is the o=
nly way to end the lifetime of a named reference. Although you *could* give=
static_cast the same special treatment, I feel it would be potentially une=
xpected (see 7.1).</div><div><br></div><blockquote class=3D"gmail_quote" st=
yle=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padd=
ing-left:1ex"><div dir=3D"ltr"><div>(3) I think your proposal is doomed bec=
ause of sections 4.2 and 4.3:</div><div><br></div><div>>=C2=A0<span styl=
e=3D"color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">=C2=A0=
if the forwarding operator is applied to an owning reference, then the dest=
ructor will no longer be called when the scope of the reference ends. We wi=
ll say that the reference is=C2=A0</span><em style=3D"color:rgb(0,0,0);font=
-family:-webkit-standard">live</em><span style=3D"color:rgb(0,0,0);font-fam=
ily:-webkit-standard;font-size:medium">=C2=A0if the forwarding operator has=
not yet been applied to it; after the operator is applied it is=C2=A0</spa=
n><em style=3D"color:rgb(0,0,0);font-family:-webkit-standard">dead</em><spa=
n style=3D"color:rgb(0,0,0);font-family:-webkit-standard;font-size:medium">=
.. If an owning reference is still live at the end of its scope, then the de=
structor of the object is invoked. So clearly it is important that the comp=
iler must be able to keep track of which references are live.</span></div><=
div><br></div><div>I think this is a proposal-killer. C++ likes to track th=
ings via the typesystem, via changes in static type. You're proposing t=
hat the compiler static-analyze the code to track "liveness" with=
out interacting with the typesystem at all: a "live" owning ref a=
nd a "dead" owning ref are completely different beasts as far as =
the compiler is concerned, but they have exactly the same static type. I do=
n't think this will fly at all. C++ is not Rust.</div><div>To your cred=
it, you know this is a problem and spend a while exploring it... but your s=
olution is too complicated to fly.</div></div></blockquote><div><br></div><=
div>I believe this is an inevitable consequence of wanting to be able to mo=
ve from objects with automatic storage duration. For this to work at all, i=
t *must* be possible for the lifetime of an object to end before the end of=
its scope. If you don't have this, you don't have destructive move=
..</div><div><br></div><div>The way I would describe is it that a dead refer=
ence doesn't even have a type. It's not valid to use the name of re=
ference in any way (maybe even decltype(r) should be forbidden - I can'=
t think of any possible uses for it).</div><div>=C2=A0</div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>(4) I don't un=
derstand your example "g1". The "else if" branch is com=
mented "OK", and the "else" branch is commented "E=
RROR", but I don't see any difference between them. Does the curly=
brace before the final "return -1" actually make a difference?=
=C2=A0 If I wrapped the first two statements of the "else if" bra=
nch in an extra pair of curly braces, so that "return val" was ou=
tside those braces, would it stop being "OK" and start being &quo=
t;ERROR"?</div></div></blockquote><div><br></div><div>The difference i=
s that execution can continue past the end of the block in one case but not=
in the other. I think you're right that I failed to provide an unambig=
uous answer to your second question. I actually think you could define it e=
ither way while still being consistent - I have a slight preference for &qu=
ot;no".</div><div><br></div><blockquote class=3D"gmail_quote" style=3D=
"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-le=
ft:1ex"><div dir=3D"ltr"><div>(5) The "destructuring" business do=
es seem to be required by your design, because otherwise you can't dest=
ructively-move from a std::pair (which is your core example). But it makes =
me very uncomfortable. The mental model for `pair` is that a pair is just i=
ts two members, and that if we destroy one member and then destroy the othe=
r member, then the pair itself will have been completely destroyed and ther=
e's no need to call any destructor. This is 100% true for `pair` =E2=80=
=94 or true enough. But what about a type with a non-trivial destructor?</d=
iv><div><br></div><div>=C2=A0 =C2=A0 struct P {</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 int *ptr_;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 P(int *p): ptr_=
(p) { ptr_->incref(); }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 P(P~ rhs) =
: ptr_(rhs.ptr_) { ptr_->incref(); } =C2=A0// FOO</div><div>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 ~P() { ptr_->decref(); }</div><div>=C2=A0 =C2=A0 };</d=
iv><div><br></div><div>IIUC, here the parameter `P~ rhs` means that FOO is =
taking responsibility for destroying the object referenced by `rhs`. Your s=
tatic-analysis stuff (which I don't like) makes sure that `rhs`'s d=
estructor gets called at the end of the scope because `rhs` was never forwa=
rded-from. So the refcounts balance out in this case.</div><div><br></div><=
div>But if we use the destructuring suffix `.*` then that basically counts =
as forwarding-from `rhs`, is that right?</div><div><br></div><div><div>=C2=
=A0 =C2=A0 struct P {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 int *ptr_;</div=
><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 P(int *p): ptr_(p) { ptr_->incref(); }=
</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 P(P~ rhs.*) : ptr_(>>rhs.ptr_)=
{ no_need_to_incref(); } =C2=A0// BAR</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 ~P() { ptr_->decref(); }</div><div>=C2=A0 =C2=A0 };</div></div><div>=
<br></div><div>Here `rhs` will not be destroyed at the end of the scope bec=
ause it was destructured, which counts as forwarding-from. Is that right?</=
div><div>In this example, if `no_need_to_incref()` throws an exception, the=
n we leak a refcount; but that's actually no different from how any con=
structor works, so I think that's okay.</div></div></blockquote><div><b=
r></div><div>Yes, this was exactly my intention.=C2=A0</div><div><br></div>=
<blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-=
left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>(6)=
A big conceptual problem with your destructuring is that it works 100% on =
bases-and-members, which is different from how C++17 structured binding wor=
ks with a customization point named std::get. =C2=A0(Mind you, C++17 struct=
ured binding is just a messy mistake. I'm not saying you should try to =
be <i>more</i> like it.) =C2=A0What this means is that your destructuring w=
ill not work to forward-out-of a tuple, for example.</div><div><br></div><d=
iv>=C2=A0 =C2=A0 void this_will_never_work(std::tuple<T, U>~ tup.*) {=
</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 T t =3D >>std::get<0>(tu=
p); =C2=A0// or whatever</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 U u =3D >=
>std::get<1>(tup);</div><div>=C2=A0 =C2=A0 }<br></div><div><br></d=
iv><div>That's because tuple elements are not stored as (direct) member=
s or (direct) bases.</div><div>This also gets back to (5), because you'=
d have to assume that destroying all the members of a tuple somehow destroy=
ed the whole tuple. Unfortunately this is again pretty much true at the mac=
hine-code level, but it continues to unnerve me at the source-code level.</=
div><div>The easiest way out is to say that yeah, destructuring doesn't=
work on tuples and you should never destructive-move-out-of a tuple elemen=
t. P1144 certainly says you should never relocate-out-of a tuple element.</=
div></div></blockquote><div><br></div><div>This is section 5.7 of my paper.=
You can move from tuple elements like this:</div><div><br></div><div>void =
this_works(std::tuple<T, U>~ tup) {</div><div>=C2=A0 =C2=A0 auto~ [t,=
u] =3D >>tup;</div><div>}</div><div><br></div><div>I agree that a na=
med customization point does not work. Maybe this is unfortunate. Or maybe =
it makes sense and std::get should really be replaced with a pure language =
feature: I agree that C++17 structured bindings are messy.</div><div><br></=
div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bor=
der-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div=
>(7) IIUC, your proposal does enable almost all the same optimizations that=
P1144 enables. You add a new kind of special member function, which can be=
defaulted, and which (when defaulted) can be analyzed by the compiler to f=
ind out if it's trivial, and which can be implicitly generated by the c=
ompiler so source code doesn't need to change.=C2=A0 So you do end up w=
ith</div><div>=C2=A0 =C2=A0 struct R { std::unique_ptr<int> m; };</di=
v><div>=C2=A0 =C2=A0 void foo(std::vector<R>& v) { v.reserve(v.ca=
pacity() + 1); }</div><div>producing a memcpy instead of a move-and-destroy=
-in-a-loop, because the compiler implicitly generates `R(R~) =3D default` a=
nd verifies that it's trivial. This matches your understanding, right?<=
/div></div></blockquote><div><br></div><div>Yes, exactly. It would be reall=
y disappointing if this didn't work.</div><div>=C2=A0</div><blockquote =
class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px sol=
id rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>(8) I say "=
;almost" all because your proposal does not contain any way for the us=
er to warrant that their `R(R~)` is trivial when it is <i>not</i> defaulted=
..</div><div><br></div><div>=C2=A0 =C2=A0 struct S {</div><div>=C2=A0 =C2=A0=
=C2=A0 =C2=A0 int i;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 boost::interpro=
cess::offset_ptr<int> p =3D &i; =C2=A0// class invariant: p alway=
s points to my own i</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 S(int i) : i(i) =
{}<br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 S(S&& rhs) { i =3D rhs=
..i; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 S(S~ rhs) { i =3D rhs.i; }</div=
><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 ~S() =3D default;</div><div>=C2=A0 =C2=A0=
};</div><div><br></div><div>Here, `S`</div><div>- is <i>actually</i> trivi=
ally destructible;</div><div>- is <i>conceptually</i>, but not actually, tr=
ivially move-constructible;</div><div>- is <i>conceptually</i>, but not act=
ually, trivially relocate-able in your terms.</div><div><br></div><div>With=
P1144's proposed attribute, the programmer could ensure that `S`</div>=
<div><div>- is=C2=A0<i>actually</i>=C2=A0trivially destructible;</div><div>=
- is=C2=A0<i>conceptually</i>, but not actually, trivially move-constructib=
le;</div><div>- is=C2=A0<i>actually</i>=C2=A0trivially relocatable in P1144=
's terms.</div></div><div><br></div><div>"What good is being <i>ac=
tually</i> trivially relocatable, if you can never be <i>actually</i> trivi=
ally move-constructible even in P1144's world?" Well, I'm not =
sure, maybe I'm putting too much weight on this property of P1144. But =
"what good is being <i>actually</i> trivially relocatable?" =E2=
=80=94 well, it enables all these nice memcpy optimizations that we really =
want to get!</div><div>Being <i>actually</i> trivially move-constructible i=
s also perhaps useful, but certainly much less frequently. (I can't thi=
nk of any uses for it off the top of my head.)</div><div><br></div><div>Of =
course you could fix this complaint by just adding a warranting attribute [=
[trivially_relocatable]] of your own =E2=80=94 in fact, vendors might do it=
without your needing to propose it. So this is a very minor complaint comp=
ared to the big ones above and below.</div></div></blockquote><div><br></di=
v><div>OK, I did wonder whether there were any examples like this, and had =
failed to think of any. But I agree that you have a valid example here.</di=
v><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div>(9) I do tend to agree with Nicol that "let's add an=
other kind of reference" is probably not going to fly in the real worl=
d. I don't think it's terribly productive to use that as the <i>onl=
y</i> reason to shoot this proposal down, though. :)</div><div><br></div><d=
iv>(10) Here are some of the properties of your "owning reference.&quo=
t; It binds only to "temporary objects" (prvalues). It indicates =
ownership and responsibility for destroying. It is neither an lvalue nor an=
rvalue reference. ...This makes me wonder: Are you <i>sure</i> you're =
not just describing a <i>non-reference, prvalue</i> type? Thought experimen=
t: Go through your examples and eliminate all the `~` sigils. What are you =
left with?=C2=A0 I'm not sure, but I optimistically imagine you're =
left with a super-powered version of copy elision, plus the ability to &quo=
t;turn an lvalue back into a prvalue" by applying either `>>` or=
`.*`, plus a sort of "prvalue constructor" signature `A(A)` whic=
h is legal only if it is `=3Ddefault`ed or if the argument is immediately `=
..*`ed. Okay, this is probably crazy. :)</div></div></blockquote><div><br></=
div><div>I don't think that's crazy. I feel an owning reference is =
midway between a reference and a value. I stopped short of making them actu=
al values because:</div><div>- You can create an owning reference to a type=
even if it is not relocatable, which seems important for generic code. I d=
on't think you can ensure copy elision in enough situations to make thi=
s work with just values. It would be really nice if you could!</div><div>- =
You need some way to declare that a function argument is to be destroyed by=
the callee. You could say, we'll pass by value, and annotate the param=
eter in some way to say that it will be destroyed by the callee. For exampl=
e, annotate the parameter by writing a tilde before the name. But then what=
you've got looks just like owning references.</div><div><br></div><div=
>Many thanks for taking the trouble to read through everything, I'm rat=
her delighted that anyone did!</div><div><br></div><div><br></div></div></d=
iv>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAB55TMrQ9oM-3iEn4aekdFVU%3DtRmZO_Kt-=
6weKydp60zqzx3_w%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAB55TMrQ9oM-3i=
En4aekdFVU%3DtRmZO_Kt-6weKydp60zqzx3_w%40mail.gmail.com</a>.<br />
--00000000000087b9d4057ff83b4e--
.
Author: =?UTF-8?Q?=27Thomas_K=C3=B6ppe=27_via_ISO_C=2B=2B_Standard_=2D_Future_Proposals?= <std-proposals@isocpp.org>
Date: Mon, 21 Jan 2019 07:04:10 -0800 (PST)
Raw View
------=_Part_1750_625406683.1548083050507
Content-Type: multipart/alternative;
boundary="----=_Part_1751_2001169658.1548083050507"
------=_Part_1751_2001169658.1548083050507
Content-Type: text/plain; charset="UTF-8"
Thanks a lot for this post! Just in case this may be of interest to you (or
anyone), I was thinking about approaching destructive moves via a new value
category (and reference type) back in 2014 when this was discussed, and I
noticed a few similarities with your idea. I don't believe my approach will
actually be palatable to the committee (it's too much complexity for a very
niche benefit), but I wrote it up a few weeks ago regardless and I'm
attaching a copy here. My approach is more restrictive than yours and
_only_ works (well) with dynamic allocations, which solves the original
motivation (a std::list whose default/move-from state contains a dynamic
allocation). It does _not_ modify how anything with automatic or static
storage works.
Are you sending your proposal to the WG21 mailing?
All the best,
Thomas
On Sunday, 20 January 2019 13:29:17 UTC, dcrc...@gmail.com wrote:
>
> I've written up a version of "destructive move" for C++, attached here.
> It's meant to be a complete version, so in particular:
> - You can safely destructively move from automatic objects.
> - It is possible to write user-defined destructive move operations.
> - It supports destructive forwarding of function arguments, so that if an
> argument to a forwarding function is a temporary object, then the target
> function can destructively move from it.
>
> This isn't meant to be a proposal for standardization: I expect that the
> language changes are far too large for there to be any chance of seeing
> something like this added to C++. But since there is continuing interest in
> "relocation", and there are partial proposals for this like P1144, I
> thought it might be worthwhile to write down what a complete version could
> look like.
>
> The summary is that there are three major language features involved:
>
> - A new kind of reference, an "owning reference". Owning references are
> similar to rvalue references in that they can bind to a temporary object.
> But owning references can be destructively moved from, whereas rvalue
> references cannot.
> - A forwarding operator, like the one proposed in P0644.
> - Destructuring operations. These might look similar to structured
> bindings. But what we want for destructive move is a *true* destructuring
> operation: this is an operation which ends the lifetime of the complete
> object and returns owning references to its subobjects.
>
> Each of these things has been suggested before in one form or another. But
> I've never seen an explanation of how they combine neatly to give a full
> destructive move implementation. That's what this write-up hopes to do.
>
> Here is a user-defined destructive move implemented this way:
>
> class C
> {
> T m_t;
> U m_u;
>
> public:
> C(C ~ other.*) : m_t(>>other.m_t), m_u(>>other.m_u) { }
> };
>
> Here the constructor parameter type is an owning reference; the
> declaration other.* indicates that destructuring takes place; and the
> initialization of members uses the forwarding operator >>.
>
> Apologies in advance if there are any inaccuracies of terminology here -
> this is my first serious attempt at writing about the language. Comments
> are very welcome; beware that the paper is rather long.
>
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6b278695-fca9-4bf1-8751-abafc7b0e0dd%40isocpp.org.
------=_Part_1751_2001169658.1548083050507
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Thanks a lot for this post! Just in case this may be =
of interest to you (or anyone), I was thinking about approaching destructiv=
e moves via a new value category (and reference type) back in 2014 when thi=
s was discussed, and I noticed a few similarities with your idea. I don'=
;t believe my approach will actually be palatable to the committee (it'=
s too much complexity for a very niche benefit), but I wrote it up a few we=
eks ago regardless and I'm attaching a copy here. My approach is more r=
estrictive than yours and _only_ works (well) with dynamic allocations, whi=
ch solves the original motivation (a std::list whose default/move-from stat=
e contains a dynamic allocation). It does _not_ modify how anything with au=
tomatic or static storage works.</div><div><br></div><div>Are you sending y=
our proposal to the WG21 mailing?</div><div><br></div><div>All the best,</d=
iv><div><br></div><div>Thomas</div><div><br></div><br><br>On Sunday, 20 Jan=
uary 2019 13:29:17 UTC, dcrc...@gmail.com wrote:<blockquote class=3D"gmail=
_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;p=
adding-left: 1ex;"><div dir=3D"ltr">I've written up a version of "=
destructive move" for C++, attached here. It's meant to be a compl=
ete version, so in particular:<div>- You can safely destructively move from=
automatic objects.</div><div>- It is possible to write user-defined destru=
ctive move operations.</div><div>- It supports destructive forwarding of fu=
nction arguments, so that if an argument to a forwarding function is a temp=
orary object, then the target function can destructively move from it.</div=
><div><br></div><div>This isn't meant to be a proposal for standardizat=
ion: I expect that the language changes are far too large for there to be a=
ny chance of seeing something like this added to C++. But since there is co=
ntinuing interest in "relocation", and there are partial proposal=
s for this like P1144, I thought it might be worthwhile to write down what =
a complete version could look like.</div><div><br></div><div>The summary is=
that there are three major language features involved:</div><div><br></div=
><div><div>- A new kind of reference, an "owning reference". Owni=
ng references are similar to rvalue references in that they can bind to a t=
emporary object. But owning references can be destructively moved from, whe=
reas rvalue references cannot.</div><div>- A forwarding operator, like the =
one proposed in P0644.</div><div>- Destructuring operations. These might lo=
ok similar to structured bindings. But what we want for destructive move is=
a *true* destructuring operation: this is an operation which ends the life=
time of the complete object and returns owning references to its subobjects=
..</div></div><div><br></div><div>Each of these things has been suggested be=
fore in one form or another. But I've never seen an explanation of how =
they combine neatly to give a full destructive move implementation. That=
9;s what this write-up hopes to do.</div><div><br></div><div>Here is a user=
-defined destructive move implemented this way:</div><div><br></div><font f=
ace=3D"courier new, monospace">class C<br>{<br>=C2=A0 =C2=A0 T m_t;<br>=C2=
=A0 =C2=A0 U m_u;<br> <br>public:<br>=C2=A0 =C2=A0 C(C ~ other.*) : m_t(=
>>other.m_t), m_u(>>other.m_u) { }<br>};</font><div><br><div><d=
iv>Here the constructor parameter type is an owning reference; the declarat=
ion <font face=3D"courier new, monospace">other.*</font> indicates that des=
tructuring takes place; and the initialization of members uses the forwardi=
ng operator >>.</div></div><div><br></div><div>Apologies in advance i=
f there are any inaccuracies of terminology here - this is my first serious=
attempt at writing about the language. Comments are very welcome; beware t=
hat the paper is rather long.</div></div></div></blockquote></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6b278695-fca9-4bf1-8751-abafc7b0e0dd%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/6b278695-fca9-4bf1-8751-abafc7b0e0dd=
%40isocpp.org</a>.<br />
------=_Part_1751_2001169658.1548083050507--
------=_Part_1750_625406683.1548083050507
Content-Type: text/html; charset=US-ASCII; name=move_destructor.html
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=move_destructor.html
X-Attachment-Id: c4b7da85-3d18-43cf-9a39-64f63d7d8c73
Content-ID: <c4b7da85-3d18-43cf-9a39-64f63d7d8c73>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<meta content="text/html;charset=UTF-8" http-equiv="Content-Type">
<title>Destructive moves via value categories</title>
<style type="text/css">
html { margin: 0; padding: 0; color: black; background-color: white; }
body { padding: 2em; font-size: medium; font-family: "DejaVu Serif", serif; line-height: 150%; }
code { font-family: "DejaVu Sans Mono", monospace; color: #006; }
h1, h2, h3 { margin: 1.5em 0 .75em 0; line-height: 125%; }
div.code { white-space: pre-line; font-family: "DejaVu Sans Mono", monospace;
border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1em;
border-radius: 4px; line-height: 200%; }
div.strictpre { white-space: pre; }
sup, sub { line-height: 0; }
.docinfo { float: right; }
.docinfo p { margin: 0; text-align:right; }
.docinfo address { font-style: normal; }
.quote { display: inline-block; clear: both; margin-left: 1ex;
border: thin solid #E0E0E0; background-color: #F8F8F8; padding: 1ex; }
.modify { border-left: thick solid #999; border-right: thick solid #999; padding: 0 1em; }
.insert { border-left: thick solid #0A0; border-right: thick solid #0A0; padding: 0 1em; }
.comment { color: #753; }
.comment a:link, .comment a:visited { color: #A51; }
table { border-top: 2px solid black; border-bottom: 2px solid black; border-collapse: collapse; margin: 3em auto; }
thead th { border-bottom: 2px solid black; }
th.sep { border-top: 2px solid black; border-bottom: 2px solid black; }
th, td { text-align: left; vertical-align: top; padding: 1ex 0; margin: 0; }
td.code { white-space: pre-line; font-family: "DejaVu Sans Mono", monospace;
padding: 1em; line-height: 150%; }
table.x { caption-side: bottom; }
table.x caption { padding-top: 1ex; }
.x th, .x td { padding: 1ex 1ex 1ex 1ex; }
.x th:first-child, .x td:first-child { padding-left: 1ex; }
td.y { padding: 0 1em; }
p.skip { margin-top: 1em; }
ins { color: #090; }
del { color: #A00; }
ins code, del code { color: inherit; }
span.new { color: #080; font-weight: bold; }
span.old { color: #800; font-weight: bold; }
#toggleparams:checked ~ * .params { display: none; }
</style>
</head>
<body>
<div class="docinfo">
<p>Date: 2019-01-21</p>
<address>Thomas Köppe <<a href="mailto:tkoeppe@google.com">tkoeppe@google.com</a>></address>
<p class="skip">ISO/IEC JTC1 SC22 WG21 D????R0</p>
<p>To: EWG (informative only)</p>
</div>
<h1>Destructive moves via value categories</h1>
<hr style="margin-top: 3em;">
<p style="font-family: 'DejaVu Sans', sans-serif; color: #800;">
This document is <em>not</em> a proposal for a change. It is merely
an exploration of a topic that has never been fully resolved.</p>
<hr>
<!-- fgrep -e "<h2 id=" move_destructor.html | sed -e 's/.*id="\(.*\)">\(.*\)<\/h2>/<li><a href="#\1">\2<\/a><\/li>/g' -->
<!-- h2>Contents</h2>
<ol>
<li><a href="#summary">Summary</a></li>
<li><a href="#references">References</a></li>
</ol -->
<!-- h2 id="history">Revision history</h2>
<ul>
<li>D????R0: this version</li>
</ul -->
<h2 id="summary">Introduction, overview and summary</h2>
<p>A <em>destructive move</em> is a hypothetical operation that at once creates one object
by “moving” from another one and also ends the lifetime of that latter
object. It is conceptually the same as a move construction followed by destruction of the
source.</p>
<p>Destructive moves are a feature similar to, but distinct from, move semantics: Both are
ways to obtain <em>mutable</em> references to objects that are near the end of their
life.</p>
<p>Previous attempts to define destructive moves have glossed over the impact on object
lifetimes (see below). Here, we adopt a principled approach that calls for a distinct,
new value category to describe values that are eligible for destructive move.</p>
<table style="width: 80%" class="x">
<col width="20%">
<col width="40%">
<col width="40%">
<thead>
<tr><th></th><th>Move semantics</th><th>Destructive moves</th></tr>
</thead>
<tbody>
<tr>
<th>Idea</th>
<td>“Unique”, mutable reference to a value</td>
<td>Reference to an object under destruction</td>
</tr>
<tr>
<th>Applicable to</th>
<td>all objects</td>
<td>objects of dynamic storage duration</td>
</tr>
<tr>
<th>Eligible values</th>
<td>rvalues (prvalues, xvalues)</td>
<td>destroyed values: “dvalues”</td>
</tr>
<tr>
<th>Type of reference</th>
<td>rvalue reference, <code>T&&</code></td>
<td>dvalue reference, <code>T~&</code></td>
</tr>
<tr>
<th>Origin of values</th>
<td>temporary objects, explicit casts to <code>T&&</code></td>
<td>explicit casts to <code>T~&</code></td>
</tr>
<tr>
<th>Special member functions</th>
<td>
move constructor: <code>T::T(T&& rhs)</code><br>
move assignment: <code>T::operator=(T&& rhs)</code><br>
<br>simple, mutable access to the object designated by <code>rhs</code>
</td>
<td>
“move destructor”: <code>T::T(T~& rhs)</code><br><br>
A destructor for the object designated by <code>rhs</code>; ends that
object’s lifetime.
</td>
</tr>
<tr>
<th>Typical example</th>
<td class="code"><span class="comment">// Destroys the old object,
// returns the address of the new object.</span>
T* move_object(T* obj, void* new_addr) {
T* new_obj = ::new (new_addr) T(std::move(*obj));
old_obj->~T();
return new_obj;
}
</td>
<td class="code"><span class="comment">// Destroys the old object,
// returns the address of the new object.</span>
T* move_object(T* obj, void* new_addr) {
return ::new (new_addr) T(static_cast<T~&>(*obj));
}
</td>
</tr>
<tr>
<th>Impact on the object model</th>
<td>none</td>
<td>
Amend [basic.life] bullet (1.3) as follows.
<div class="modify">The lifetime of an object <em>o</em> of type <code>T</code>
ends when […] the destructor call <ins>or move destructor call</ins>
starts […]</div></td>
</tr>
</tbody>
</table>
<h2>Motivation</h2>
<p>A destructive move is a strict optimization where object lifetimes are
managed dynamically (= manually). The poster-child example is the
reallocation inside a growing <code>std::vector<T></code>: new
memory is allocated, existing container elements need to be moved to the
new location, the old objects need to be destroyed, and the old memory
is deallocated. There are two avoidable costs here:</p>
<ul>
<li>Destructors need to be called for the old objects, even if the
destructors end up <em>dynamically</em> doing nothing (e.g. when
a vector of unique pointers reallocates.</li>
<li>Sometimes a move operation cannot be noexcept if move construction
and destruction are separately non-trivial, but jointly trivial.</li>
</ul>
<p>The first point is general and interesting on its own, but let us explore
the second point in more detail. That point is motivated by a real implementation
of <code>std::list</code>, where the list always contains a dynamically allocated
sentinel node. The move constructor needs to reallocate a new sentinel for the
moved-from object, and the destructor deletes it. Schematically:</p>
<div class="code">struct List {
Node* head;
List() : head(new Node) {}
List(List&& rhs) : head(rhs.head) { rhs.head = new Node; }
~List() {
DeleteAll(); <span class="comment">// delete all elements</span>
delete head; <span class="comment">// delete sentinel; expect head != nullptr</span>
}
};</div>
<p>Note that neither move nor default constructor can be <code>noexcept</code>
in this design. Practically, a <code>std::vector<List></code> would not
even move elements during reallocation but <em>copy</em> them so as to provide
the strong exception guarantee.</p>
<p>With destructive moves, we can offer a <code>noexcept</code> move destructor:</p>
<div class="code">struct List {
<span class="comment">// all members as before</span>
List(List~& rhs) noexcept : head(rhs.head) { <span class="comment">/* OK to "leak" rhs.head here! */</span> }
};</div>
<h2>Discussion</h2>
<p>Destructive moves are a more radical and more niche relative of move semantics.</p>
<p>Move semantics are about getting a mutable reference to an object that
is either not aliased at all, or which a user has explicitly decoupled
from existing aliases. Powerful as this feature is, it is ultimately just
about getting a reference to an object. Most importantly, there is nothing
special about the referenced object: it continues to be a regular object
with a regular life cycle; it exists past the move operation and is
(typically) eventually destroyed. As far as the source object is concerned,
a <em>move</em> is just a regular mutating access.</p>
<p>By contrast, destructive moves are about object <em>lifetimes</em>. A destructive
move ends the source object’s lifetime, just as a destructor call does.
Destructors are usually called as a result of an object having reached its
end of life. They are usually only called explicitly on dynamically created
objects (i.e. objects created via placement-new). Similarly, a destructive move
is mostly useful for dynamically created objects. As far as the source object is
concerned, a destructive move is a destructor call.</p>
<p>The key to move semantics <em>and</em> destructive moves lies in
<em>value categories</em>. Value categories allow us to address the
point in an object’s life cycle: a value with no aliases
or explicitly decoupled aliases is prvalue (a temporary value before
materialisation) or an xvalue (e.g. a member of a prvalue, or the result
of an explicit cast). Collectively, prvalues and xvalues are rvalues,
and those are precisely the values that we can move from, and for which we
have a dedicated type of reference.</p>
<p>Similarly, we need a way to designate a value that is not just
“no longer used”, but actually <em>at</em> the end
of its lifetime. Existing value categories do not cover this
case, since rvalues designate live objects only. We consider thus
a new value category, tentatively called <em>dvalue</em> (for
“destroyed value”), which is the value of an object that
is currently being destroyed. There is a new reference type for it,
the <em>dvalue reference</em>, tentatively spelled <code>~&</code>,
and the only way to obtain a dvalue is to cast a value of type <code>T</code>
to dvalue via <code>static_cast<T~&></code>.</p>
<p>The main design addition of this approach to destructive moves is a new
special member function, <code>T::T(T~& rhs)</code>, that is at once
a constructor for <code>T</code> that has mutable access to <code>rhs</code>,
<em>as well as</em> the body of a destructor for <code>rhs</code>. Once
this function has returned, the lifetime of <code>rhs</code> has ended.
We call this function a <code>move destructor</code> for <code>T</code>.</p>
<p>Since the only way to obtain a dvalue is via an explicit cast,
a move destructor is precisely appropriate in situations where an
explicit destructor call is appropriate:</p>
<table>
<tbody>
<tr>
<td class="code" style="width: 20em"><!--
-->alignas(T) char buf[sizeof(T)];
T* p = new (buf) T(args...);
T x(std::move(*p));
p->~T();
</td>
<td class="code" style="width: 20em"><!--
-->alignas(T) char buf[sizeof(T)];
T* p = new (buf) T(args...);
T x(static_cast<T~&>(*p));
<span class="comment">// only one T object alive here</span>
</td>
</tr>
</tbody>
</table>
<p>Note that the destruction is the result of binding to a move destructor,
not merely of the cast-to-dvalue! Just as the unary <code>std::move</code>
“doesn’t move anything”, a cast-to-destroyed-value does
not destroy anything. Rather, it is the binding to an appropriate function
that “does something”.
<h2>Downsides</h2>
<ul>
<li>A big extension of the fundamental expression model of the language for
a rather narrow and niche gain.</li>
<li>Lack of generality: dvalue references are probably not useful outside
of move destructors.</li>
<li>Has nothing to do with automatic and temporary-lifetime storage.
E.g. cannot be used to improve performance of returning unique pointers
by value (except with major contortions).
</ul>
<h2 id="references">References</h2>
<ul>
<li>Pablo Halpern, <em>Destructive Move</em>.
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4034.pdf">N4034</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4158.pdf">N4158</a>.
</li>
<li>Pablo Halpern, <em>Noop Constructors and Destructors</em>.
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4393.pdf">N4393</a>.
</li>
<li>Sean Parent, <em><a
href="https://github.com/sean-parent/sean-parent.github.io/wiki/Non-Proposal-for-Destructive-Move">Non
Proposal for Destructive Move</a></em>. See also a <a
href="https://github.com/mcalabrese/cpp-stuff/wiki/std::move-Is-Not-Destructive-Move">response
by Matt Calabrese</a>.</li>
<li>Denis Bider, <em>Relocator: Efficiently moving objects</em>.
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0023r0.pdf">P0023R0</a>.
(This paper does not appear to have been discussed.)
</li>
<li>Niall Douglas, <em><code>[[move_relocates]]</code></em>:
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1029r0.html">P1029R0</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1029r1.html">P1029R1</a>.
</li>
<li>Arthur O’Dwyer et al., <em>Object relocation in terms of move plus destroy</em> (authors vary):
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html">P1144R0</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r1.html">P1144R1</a>.
</li>
<li>Arthur O’Dwyer, David Stone, <em>More implicit moves</em>:
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1155r0.html">P1155R0</a>,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1155r1.html">P1155R1</a>.
</li>
</ul>
</body>
</html>
------=_Part_1750_625406683.1548083050507--
.
Author: David Collier <dcrc2cpp@gmail.com>
Date: Mon, 21 Jan 2019 17:01:01 +0000
Raw View
--000000000000d968c2057ffacef3
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Mon, Jan 21, 2019 at 3:04 PM Thomas K=C3=B6ppe <tkoeppe@google.com> wrot=
e:
> Thanks a lot for this post! Just in case this may be of interest to you
> (or anyone), I was thinking about approaching destructive moves via a new
> value category (and reference type) back in 2014 when this was discussed,
> and I noticed a few similarities with your idea. I don't believe my
> approach will actually be palatable to the committee (it's too much
> complexity for a very niche benefit), but I wrote it up a few weeks ago
> regardless and I'm attaching a copy here. My approach is more restrictive
> than yours and _only_ works (well) with dynamic allocations, which solves
> the original motivation (a std::list whose default/move-from state contai=
ns
> a dynamic allocation). It does _not_ modify how anything with automatic o=
r
> static storage works.
>
Thank you - that's really interesting and definitely more similar to my
version than anything else I know of.
It looks like a big difference between our approaches is that you say "a
cast-to-destroyed-value does not destroy anything", whereas in my version,
if you cast to an owning reference, the referred-to object will be always
destroyed on that line of code in one way or another. I felt this was
important for something like your example:
T x(static_cast<T~&>(*p));
If you know that T has a move destructor then this is fine. What happens if
T has only a normal move constructor, or only a copy constructor? In my
version, the normal move constructor can be found by overload resolution,
and it has the correct effect: the source object is destroyed at the end of
the full expression, after it has been (non-destructively) moved from. In
your version, how would you ensure that the source is properly destroyed
when only the normal move constructor is available? Do you require the
compiler to generate a move destructor for all types which don't explicitly
provide it? Or do you need to know whether T has a move destructor before
you decide to so a static_cast<T~&>?
Are you sending your proposal to the WG21 mailing?
>
Maybe, if no-one points out any serious flaws. I'm a bit hesitant though
because, not having submitted a paper before, something this long and
complex would be a pretty crazy place to start. It's not meant to be a
proposal anyway - it's too complicated to become a part of C++ - but I was
hoping it might provide useful context for P1144 and similar.
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAB55TMr%3DgARuhDnQWWRPi%2BhhA6Nu2oQBsadGMQWQNT7=
Z4Vuw8g%40mail.gmail.com.
--000000000000d968c2057ffacef3
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr">On Mon, Jan 21, 2019 at 3:04 PM Thomas K=
=C3=B6ppe <<a href=3D"mailto:tkoeppe@google.com">tkoeppe@google.com</a>&=
gt; wrote:<br></div><div class=3D"gmail_quote"><blockquote class=3D"gmail_q=
uote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,2=
04);padding-left:1ex"><div dir=3D"ltr"><div>Thanks a lot for this post! Jus=
t in case this may be of interest to you (or anyone), I was thinking about =
approaching destructive moves via a new value category (and reference type)=
back in 2014 when this was discussed, and I noticed a few similarities wit=
h your idea. I don't believe my approach will actually be palatable to =
the committee (it's too much complexity for a very niche benefit), but =
I wrote it up a few weeks ago regardless and I'm attaching a copy here.=
My approach is more restrictive than yours and _only_ works (well) with dy=
namic allocations, which solves the original motivation (a std::list whose =
default/move-from state contains a dynamic allocation). It does _not_ modif=
y how anything with automatic or static storage works.</div></div></blockqu=
ote><div><br></div><div>Thank you - that's really interesting and defin=
itely more similar to my version than anything else I know of.</div><div><b=
r></div><div>It looks like a big difference between our approaches is that =
you say "<span style=3D"color:rgb(0,0,0);font-family:"DejaVu Seri=
f",serif;font-size:medium">a cast-to-destroyed-value does not destroy =
anything",</span>=C2=A0 whereas in my version, if you cast to an ownin=
g reference, the referred-to object will be always destroyed on that line o=
f code in one way or another. I felt this was important for something like =
your example:</div><div><br></div><div>T x(static_cast<T~&>(*p));=
</div><div><br></div><div>If you know that T has a move destructor then thi=
s is fine. What happens if T has only a normal move constructor, or only a =
copy constructor? In my version, the normal move constructor can be found b=
y overload resolution, and it has the correct effect: the source object is =
destroyed at the end of the full expression, after it has been (non-destruc=
tively) moved from. In your version, how would you ensure that the source i=
s properly destroyed when only the normal move constructor is available? Do=
you require the compiler to generate a move destructor for all types which=
don't explicitly provide it? Or do you need to know whether T has a mo=
ve destructor before you decide to so a static_cast<T~&>?</div><d=
iv><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px =
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"=
ltr"><div>Are you sending your proposal to the WG21 mailing?</div></div></b=
lockquote><div><br></div><div>Maybe, if no-one points out any serious flaws=
.. I'm a bit hesitant though because, not having submitted a paper befor=
e, something this long and complex would be a pretty crazy place to start. =
It's not meant to be a proposal anyway - it's too complicated to be=
come a part of C++ - but I was hoping it might provide useful context for P=
1144 and similar.</div><div><br></div></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAB55TMr%3DgARuhDnQWWRPi%2BhhA6Nu2oQB=
sadGMQWQNT7Z4Vuw8g%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
>https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAB55TMr%3DgA=
RuhDnQWWRPi%2BhhA6Nu2oQBsadGMQWQNT7Z4Vuw8g%40mail.gmail.com</a>.<br />
--000000000000d968c2057ffacef3--
.
Author: =?UTF-8?Q?=27Thomas_K=C3=B6ppe=27_via_ISO_C=2B=2B_Standard_=2D_Future_Proposals?= <std-proposals@isocpp.org>
Date: Mon, 21 Jan 2019 09:07:56 -0800 (PST)
Raw View
------=_Part_2056_2063358929.1548090476575
Content-Type: multipart/alternative;
boundary="----=_Part_2057_136939795.1548090476575"
------=_Part_2057_136939795.1548090476575
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Monday, 21 January 2019 17:01:16 UTC, David Collier wrote:
>
> On Mon, Jan 21, 2019 at 3:04 PM Thomas K=C3=B6ppe <tko...@google.com=20
> <javascript:>> wrote:
>
>> Thanks a lot for this post! Just in case this may be of interest to you=
=20
>> (or anyone), I was thinking about approaching destructive moves via a ne=
w=20
>> value category (and reference type) back in 2014 when this was discussed=
,=20
>> and I noticed a few similarities with your idea. I don't believe my=20
>> approach will actually be palatable to the committee (it's too much=20
>> complexity for a very niche benefit), but I wrote it up a few weeks ago=
=20
>> regardless and I'm attaching a copy here. My approach is more restrictiv=
e=20
>> than yours and _only_ works (well) with dynamic allocations, which solve=
s=20
>> the original motivation (a std::list whose default/move-from state conta=
ins=20
>> a dynamic allocation). It does _not_ modify how anything with automatic =
or=20
>> static storage works.
>>
>
> Thank you - that's really interesting and definitely more similar to my=
=20
> version than anything else I know of.
>
> It looks like a big difference between our approaches is that you say "a=
=20
> cast-to-destroyed-value does not destroy anything", whereas in my=20
> version, if you cast to an owning reference, the referred-to object will =
be=20
> always destroyed on that line of code in one way or another. I felt this=
=20
> was important for something like your example:
>
> T x(static_cast<T~&>(*p));
>
> If you know that T has a move destructor then this is fine. What happens=
=20
> if T has only a normal move constructor, or only a copy constructor? In m=
y=20
> version, the normal move constructor can be found by overload resolution,=
=20
> and it has the correct effect: the source object is destroyed at the end =
of=20
> the full expression, after it has been (non-destructively) moved from. In=
=20
> your version, how would you ensure that the source is properly destroyed=
=20
> when only the normal move constructor is available? Do you require the=20
> compiler to generate a move destructor for all types which don't explicit=
ly=20
> provide it? Or do you need to know whether T has a move destructor before=
=20
> you decide to so a static_cast<T~&>?
>
The new move destructor would never be implied. The code you showed would=
=20
not compile if no such function was declared, and so you know that if this=
=20
compiles, it *will* leave *p destroyed.
=20
> Are you sending your proposal to the WG21 mailing?
>>
>
> Maybe, if no-one points out any serious flaws. I'm a bit hesitant though=
=20
> because, not having submitted a paper before, something this long and=20
> complex would be a pretty crazy place to start. It's not meant to be a=20
> proposal anyway - it's too complicated to become a part of C++ - but I wa=
s=20
> hoping it might provide useful context for P1144 and similar.
>
OK, that sounds reasonable. I agree that this is probably just "too far out=
=20
there", but it's nice to explore the design space a bit.
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/498983c9-8a9a-4928-afe1-6a72b869d2f0%40isocpp.or=
g.
------=_Part_2057_136939795.1548090476575
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Monday, 21 January 2019 17:01:16 UTC, David Collier wr=
ote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div dir=
=3D"ltr">On Mon, Jan 21, 2019 at 3:04 PM Thomas K=C3=B6ppe <<a href=3D"j=
avascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"iBqi6RQpFQAJ" rel=3D=
"nofollow" onmousedown=3D"this.href=3D'javascript:';return true;" o=
nclick=3D"this.href=3D'javascript:';return true;">tko...@google.com=
</a>> wrote:<br></div><div class=3D"gmail_quote"><blockquote class=3D"gm=
ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,=
204,204);padding-left:1ex"><div dir=3D"ltr"><div>Thanks a lot for this post=
! Just in case this may be of interest to you (or anyone), I was thinking a=
bout approaching destructive moves via a new value category (and reference =
type) back in 2014 when this was discussed, and I noticed a few similaritie=
s with your idea. I don't believe my approach will actually be palatabl=
e to the committee (it's too much complexity for a very niche benefit),=
but I wrote it up a few weeks ago regardless and I'm attaching a copy =
here. My approach is more restrictive than yours and _only_ works (well) wi=
th dynamic allocations, which solves the original motivation (a std::list w=
hose default/move-from state contains a dynamic allocation). It does _not_ =
modify how anything with automatic or static storage works.</div></div></bl=
ockquote><div><br></div><div>Thank you - that's really interesting and =
definitely more similar to my version than anything else I know of.</div><d=
iv><br></div><div>It looks like a big difference between our approaches is =
that you say "<span style=3D"color:rgb(0,0,0);font-family:"DejaVu=
Serif",serif;font-size:medium">a cast-to-destroyed-value does not des=
troy anything",</span>=C2=A0 whereas in my version, if you cast to an =
owning reference, the referred-to object will be always destroyed on that l=
ine of code in one way or another. I felt this was important for something =
like your example:</div><div><br></div><div>T x(static_cast<T~&>(=
*p));</div><div><br></div><div>If you know that T has a move destructor the=
n this is fine. What happens if T has only a normal move constructor, or on=
ly a copy constructor? In my version, the normal move constructor can be fo=
und by overload resolution, and it has the correct effect: the source objec=
t is destroyed at the end of the full expression, after it has been (non-de=
structively) moved from. In your version, how would you ensure that the sou=
rce is properly destroyed when only the normal move constructor is availabl=
e? Do you require the compiler to generate a move destructor for all types =
which don't explicitly provide it? Or do you need to know whether T has=
a move destructor before you decide to so a static_cast<T~&>?</d=
iv></div></div></blockquote><div><br></div><div>The new move destructor wou=
ld never be implied. The code you showed would not compile if no such funct=
ion was declared, and so you know that if this compiles, it <i>will</i> lea=
ve *p destroyed.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div dir=3D"ltr"><div class=3D"gmail_quote"><blockquote class=3D"g=
mail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204=
,204,204);padding-left:1ex"><div dir=3D"ltr"><div>Are you sending your prop=
osal to the WG21 mailing?</div></div></blockquote><div><br></div><div>Maybe=
, if no-one points out any serious flaws. I'm a bit hesitant though bec=
ause, not having submitted a paper before, something this long and complex =
would be a pretty crazy place to start. It's not meant to be a proposal=
anyway - it's too complicated to become a part of C++ - but I was hopi=
ng it might provide useful context for P1144 and similar.</div></div></div>=
</blockquote><div><br></div><div>OK, that sounds reasonable. I agree that t=
his is probably just "too far out there", but it's nice to ex=
plore the design space a bit.</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/498983c9-8a9a-4928-afe1-6a72b869d2f0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/498983c9-8a9a-4928-afe1-6a72b869d2f0=
%40isocpp.org</a>.<br />
------=_Part_2057_136939795.1548090476575--
------=_Part_2056_2063358929.1548090476575--
.
Author: Nicol Bolas <jmckesson@gmail.com>
Date: Mon, 21 Jan 2019 10:32:28 -0800 (PST)
Raw View
------=_Part_2124_372852324.1548095548383
Content-Type: multipart/alternative;
boundary="----=_Part_2125_1693843354.1548095548384"
------=_Part_2125_1693843354.1548095548384
Content-Type: text/plain; charset="UTF-8"
On Sunday, January 20, 2019 at 5:26:53 PM UTC-5, Tony V E wrote:
>
> Dangling references and destructive move are two things that could
> possibly be solved by something called 'owning references'.
>
> I haven't read the paper, but the high cost of another reference could be
> worth it if it solved these issues.
>
.... huh.
A while back, I went exploring down the rabbit hole of dangling references.
At some point, I realized that what I was about to define was de-facto
another reference type (along with further subdividing xvalues into two new
value categories). At which point I deemed the whole exploration to be
insane and stopped.
Would a third reference type be worth it if it solved both destructive move
(at a language level) and dangling reference? I don't know.
The big problem with third references is that you're adding greater
complexity to a part of the language that already has a lot of complexity.
Reference collapsing rules already have 4 cases; adding a new reference
type makes 8 cases. You now have a third case where they get applied to
`this`, but you also have to decide how that interacts with the other two
`this` reference.
It's hard enough to teach beginning C++ programmers how to use rvalue
references correctly. The distinction between genuine rvalue references and
forwarding references, when and how to use `move`, etc.
This is why solving the dangling reference problem through a third
reference makes a degree of sense: that's an area of the language that is
already complex for C++ users; if adding a bit more complexity allows users
to write working code, then it's a win.
By contrast, solving destructive move alone is adding complexity without
removing complexity. It (potentially) adds performance, but at the cost of
complexity in a domain that C++ is already over-complicated within.
So I guess I could say this: if you can solve both problems with the same
mechanism, it might be worth doing.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/057b85fb-1020-4119-a6a5-19eb251f7057%40isocpp.org.
------=_Part_2125_1693843354.1548095548384
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Sunday, January 20, 2019 at 5:26:53 PM UTC-5, Tony V E =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"background=
-color:rgb(255,255,255);line-height:initial" lang=3D"en-US"> =
<div=
style=3D"width:100%;font-size:initial;font-family:Calibri,'Slate Pro&#=
39;,sans-serif,sans-serif;color:rgb(31,73,125);text-align:initial;backgroun=
d-color:rgb(255,255,255)">Dangling references and destructive move are two =
things that could possibly be solved by something called 'owning refere=
nces'.</div><div style=3D"width:100%;font-size:initial;font-family:Cali=
bri,'Slate Pro',sans-serif,sans-serif;color:rgb(31,73,125);text-ali=
gn:initial;background-color:rgb(255,255,255)"><br></div><div style=3D"width=
:100%;font-size:initial;font-family:Calibri,'Slate Pro',sans-serif,=
sans-serif;color:rgb(31,73,125);text-align:initial;background-color:rgb(255=
,255,255)">I haven't read the paper, but the high cost of another refer=
ence could be worth it if it solved these issues.</div></div></blockquote><=
div><br></div><div>... huh.</div><div><br></div><div>A while back, I went e=
xploring down the rabbit hole of dangling references. At some point, I real=
ized that what I was about to define was de-facto another reference type (a=
long with further subdividing xvalues into two new value categories). At wh=
ich point I deemed the whole exploration to be insane and stopped.</div><di=
v><br></div><div>Would a third reference type be worth it if it solved both=
destructive move (at a language level) and dangling reference? I don't=
know.</div><div><br></div><div>The big problem with third references is th=
at you're adding greater complexity to a part of the language that alre=
ady has a lot of complexity. Reference collapsing rules already have 4 case=
s; adding a new reference type makes 8 cases. You now have a third case whe=
re they get applied to `this`, but you also have to decide how that interac=
ts with the other two `this` reference.<br></div><div><br></div><div>It'=
;s hard enough to teach beginning C++ programmers how to use rvalue referen=
ces correctly. The distinction between genuine rvalue references and forwar=
ding references, when and how to use `move`, etc.</div><div><br></div><div>=
This is why solving the dangling reference problem through a third referenc=
e makes a degree of sense: that's an area of the language that is alrea=
dy complex for C++ users; if adding a bit more complexity allows users to w=
rite working code, then it's a win.</div><div><br></div><div>By contras=
t, solving destructive move alone is adding complexity without removing com=
plexity. It (potentially) adds performance, but at the cost of complexity i=
n a domain that C++ is already over-complicated within.</div><div><br></div=
><div>So I guess I could say this: if you can solve both problems with the =
same mechanism, it might be worth doing.</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/057b85fb-1020-4119-a6a5-19eb251f7057%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/057b85fb-1020-4119-a6a5-19eb251f7057=
%40isocpp.org</a>.<br />
------=_Part_2125_1693843354.1548095548384--
------=_Part_2124_372852324.1548095548383--
.
Author: "'Niall Douglas' via ISO C++ Standard - Future Proposals" <std-proposals@isocpp.org>
Date: Tue, 22 Jan 2019 08:52:23 -0800 (PST)
Raw View
------=_Part_2583_458244079.1548175943987
Content-Type: multipart/alternative;
boundary="----=_Part_2584_1107841023.1548175943987"
------=_Part_2584_1107841023.1548175943987
Content-Type: text/plain; charset="UTF-8"
For me personally, the gains for adding a new reference type to C++ would
have to be enormous and game changing to be worth it.
I also, personally, speaking, think it's the wrong approach. For Cologne I
intend to propose to SG12 a new memory and object model which just happens
to implement object relocation as a side effect, but its main goal is to
add awareness to C++ of memory paging.
Under what I have in mind, all C++ objects anywhere in the universe
actually live in a theoretical object store somewhere, and what each C++
program sees is merely those objects attached to the current running C++
program. You can detach an object, the memory where it is stored goes from
a T to byte[sizeof(T)] i.e. T's lifetime ends and an array of byte begins,
atomically. You can relocate those bytes by memcpy(), or page table
manipulation, or whatever, as an array of bytes is trivially copyable. You
then can reattach that object back into the current running C++ program at
a new address, thus turning byte[sizeof(T)] back into a living T.
So you don't get destructive moves exactly, but you do get to relocate an
object in memory arbitrarily. You can also detach and object and hand it
off to another C++ program running elsewhere, thus implementing shared
memory support.
Anyway, this is the Kona meeting which I cannot attend, and my single
biggest work item right now is finishing Boost.Outcome's documentation, and
finding new employment. So all this is kicked down the road to Cologne.
Though I will be speaking on this topic at ACCU 2019, and discussing it
with WG14 C at their next meeting in London before presenting a paper to
SG12 in Cologne. Long road ahead.
Niall
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c8a16eb3-c065-4c9a-ac4d-148a81201fa9%40isocpp.org.
------=_Part_2584_1107841023.1548175943987
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>For me personally, the gains for adding a new referen=
ce type to C++ would have to be enormous and game changing to be worth it.<=
/div><div><br></div><div>I also, personally, speaking, think it's the w=
rong approach. For Cologne I intend to propose to SG12 a new memory and obj=
ect model which just happens to implement object relocation as a side effec=
t, but its main goal is to add awareness to C++ of memory paging.</div><div=
><br></div><div>Under what I have in mind, all C++ objects anywhere in the =
universe actually live in a theoretical object store somewhere, and what ea=
ch C++ program sees is merely those objects attached to the current running=
C++ program. You can detach an object, the memory where it is stored goes =
from a T to byte[sizeof(T)] i.e. T's lifetime ends and an array of byte=
begins, atomically. You can relocate those bytes by memcpy(), or page tabl=
e manipulation, or whatever, as an array of bytes is trivially copyable. Yo=
u then can reattach that object back into the current running C++ program a=
t a new address, thus turning byte[sizeof(T)] back into a living T.</div><d=
iv><br></div><div>So you don't get destructive moves exactly, but you d=
o get to relocate an object in memory arbitrarily. You can also detach and =
object and hand it off to another C++ program running elsewhere, thus imple=
menting shared memory support.</div><div><br></div><div>Anyway, this is the=
Kona meeting which I cannot attend, and my single biggest work item right =
now is finishing Boost.Outcome's documentation, and finding new employm=
ent. So all this is kicked down the road to Cologne. Though I will be speak=
ing on this topic at ACCU 2019, and discussing it with WG14 C at their next=
meeting in London before presenting a paper to SG12 in Cologne. Long road =
ahead.</div><div><br></div><div>Niall<br></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c8a16eb3-c065-4c9a-ac4d-148a81201fa9%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c8a16eb3-c065-4c9a-ac4d-148a81201fa9=
%40isocpp.org</a>.<br />
------=_Part_2584_1107841023.1548175943987--
------=_Part_2583_458244079.1548175943987--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Tue, 22 Jan 2019 13:04:22 -0500
Raw View
--000000000000b91ab305800fce80
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Tue, Jan 22, 2019 at 11:52 AM 'Niall Douglas' via ISO C++ Standard -
Future Proposals <std-proposals@isocpp.org> wrote:
> For me personally, the gains for adding a new reference type to C++ would
> have to be enormous and game changing to be worth it.
>
> I also, personally, speaking, think it's the wrong approach. For Cologne =
I
> intend to propose to SG12 a new memory and object model which just happen=
s
> to implement object relocation as a side effect, but its main goal is to
> add awareness to C++ of memory paging.
>
> Under what I have in mind, all C++ objects anywhere in the universe
> actually live in a theoretical object store somewhere, and what each C++
> program sees is merely those objects attached to the current running C++
> program. You can detach an object, the memory where it is stored goes fro=
m
> a T to byte[sizeof(T)] i.e. T's lifetime ends and an array of byte begins=
,
> atomically. You can relocate those bytes by memcpy(), or page table
> manipulation, or whatever, as an array of bytes is trivially copyable. Yo=
u
> then can reattach that object back into the current running C++ program a=
t
> a new address, thus turning byte[sizeof(T)] back into a living T.
>
> So you don't get destructive moves exactly, but you do get to relocate an
> object in memory arbitrarily. You can also detach and object and hand it
> off to another C++ program running elsewhere, thus implementing shared
> memory support.
>
I quite like this way of thinking about it!
However, would you agree that
- there's a set of types (such as `int`) which can be "ended, relocated,
and revived" in this way without any ill effects
- there's a set of types (such as `offset_ptr<int>`) which, if they are
ended, relocated, and revived, you'll get undefined behavior for sure
- there's a set of types (such as `std::string`) which can be ended,
relocated, and revived, but only within a single process, not across
processes
?
I think it would be a problem for me if we standardized only the *physical
mechanism* for ending and reviving, without also standardizing ways for the
programmer to use the type-system to statically prove that they were using
the physical mechanism only in ways that didn't lead to undefined behavior.
Remember, people can already do exactly what you're describing, today; and
people *do* do it. The *only* additional value a proposal can bring to the
table is to make it "not-undefined-behavior" to do this stuff. (But it
*must* remain undefined behavior in some cases, like the example of
relocating a std::string between processes in different address spaces. So
the programmer needs a way to distinguish the stuff that's okay-to-do from
the stuff that's undefined.)
=E2=80=93Arthur
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CADvuK0JB4_ZoZMFnFgag1efjsH%2B3gFTMRmdiVU5Z2-Jfg=
NxXQQ%40mail.gmail.com.
--000000000000b91ab305800fce80
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr">On Tue, Jan 22, 2019 at 11:52 AM 'Nia=
ll Douglas' via ISO C++ Standard - Future Proposals <<a href=3D"mail=
to:std-proposals@isocpp.org">std-proposals@isocpp.org</a>> wrote:<br></d=
iv><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"ma=
rgin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border=
-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>For me=
personally, the gains for adding a new reference type to C++ would have to=
be enormous and game changing to be worth it.</div><div><br></div><div>I a=
lso, personally, speaking, think it's the wrong approach. For Cologne I=
intend to propose to SG12 a new memory and object model which just happens=
to implement object relocation as a side effect, but its main goal is to a=
dd awareness to C++ of memory paging.</div><div><br></div><div>Under what I=
have in mind, all C++ objects anywhere in the universe actually live in a =
theoretical object store somewhere, and what each C++ program sees is merel=
y those objects attached to the current running C++ program. You can detach=
an object, the memory where it is stored goes from a T to byte[sizeof(T)] =
i.e. T's lifetime ends and an array of byte begins, atomically. You can=
relocate those bytes by memcpy(), or page table manipulation, or whatever,=
as an array of bytes is trivially copyable. You then can reattach that obj=
ect back into the current running C++ program at a new address, thus turnin=
g byte[sizeof(T)] back into a living T.</div><div><br></div><div>So you don=
't get destructive moves exactly, but you do get to relocate an object =
in memory arbitrarily. You can also detach and object and hand it off to an=
other C++ program running elsewhere, thus implementing shared memory suppor=
t.</div></div></blockquote><div><br></div><div>I quite like this way of thi=
nking about it!</div><div><br></div><div>However, would you agree that</div=
><div>- there's a set of types (such as `int`) which can be "ended=
, relocated, and revived" in this way without any ill effects</div><di=
v>- there's a set of types (such as `offset_ptr<int>`) which, if =
they are ended, relocated, and revived, you'll get undefined behavior f=
or sure</div><div>- there's a set of types (such as `std::string`) whic=
h can be ended, relocated, and revived, but only within a single process, n=
ot across processes</div><div>?</div><div>I think it would be a problem for=
me if we standardized only the <i>physical mechanism</i> for ending and re=
viving, without also standardizing ways for the programmer to use the type-=
system to statically prove that they were using the physical mechanism only=
in ways that didn't lead to undefined behavior.</div><div>Remember, pe=
ople can already do exactly what you're describing, today; and people <=
i>do</i> do it. The <i>only</i> additional value a proposal can bring to th=
e table is to make it "not-undefined-behavior" to do this stuff. =
=C2=A0(But it <i>must</i> remain undefined behavior in some cases, like the=
example of relocating a std::string between processes in different address=
spaces. So the programmer needs a way to distinguish the stuff that's =
okay-to-do from the stuff that's undefined.)</div><div><br></div><div>=
=E2=80=93Arthur</div></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CADvuK0JB4_ZoZMFnFgag1efjsH%2B3gFTMRm=
diVU5Z2-JfgNxXQQ%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0JB4_ZoZM=
FnFgag1efjsH%2B3gFTMRmdiVU5Z2-JfgNxXQQ%40mail.gmail.com</a>.<br />
--000000000000b91ab305800fce80--
.
Author: dcrc2cpp@gmail.com
Date: Sat, 9 Feb 2019 11:22:56 -0800 (PST)
Raw View
------=_Part_61_307303625.1549740176606
Content-Type: multipart/alternative;
boundary="----=_Part_62_919287694.1549740176606"
------=_Part_62_919287694.1549740176606
Content-Type: text/plain; charset="UTF-8"
An updated version of this paper is now
at https://github.com/dcrc2cpp/destructive-move
The main change is that the role of "owning references" has been
downplayed: owning reference variables have been renamed "moveable values",
and they have been made more like non-reference variables. They can be
initialized from an lvalue or rvalue reference, which was previously
disallowed - this now calls the copy constructor or move constructor as
appropriate, just as if a non-reference variable was being initialized.
Also the behaviour of the forwarding operator has been rephrased in terms
of changes to the scoping rules: the forwarding operator ends the scope of
the reference that it applies to. Hopefully this better explains what is
going on: the compiler does not have to track the lifetime of objects - the
lifetime of an object is determined by the scope of the variable that
refers to it.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/91aa6796-9935-4a02-8021-0e35264811a0%40isocpp.org.
------=_Part_62_919287694.1549740176606
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">An updated version of this paper is now at=C2=A0https://gi=
thub.com/dcrc2cpp/destructive-move<div><br></div><div>The main change is th=
at the role of "owning references" has been downplayed: owning re=
ference variables have been renamed "moveable values", and they h=
ave been made more like non-reference variables. They can be initialized fr=
om an lvalue or rvalue reference, which was previously disallowed - this no=
w calls the copy constructor or move constructor as appropriate, just as if=
a non-reference variable was being initialized.</div><div><br></div><div>A=
lso the behaviour of the forwarding operator has been rephrased in terms of=
changes to the scoping rules: the forwarding operator ends the scope of th=
e reference that it applies to. Hopefully this better explains what is goin=
g on: the compiler does not have to track the lifetime of objects - the lif=
etime of an object is determined by the scope of the variable that refers t=
o it.</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/91aa6796-9935-4a02-8021-0e35264811a0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/91aa6796-9935-4a02-8021-0e35264811a0=
%40isocpp.org</a>.<br />
------=_Part_62_919287694.1549740176606--
------=_Part_61_307303625.1549740176606--
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Sun, 10 Feb 2019 11:42:02 -0500
Raw View
--0000000000009bda7b05818cdb07
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Hi David,
Here's my laundry list of comments on the current draft. Nothing big here,
just a lot of nitpicks. :)
(1) Is the README on that repo still an accurate summary of the paper's
contents?
(2) The README should include a prominent link to a rendered version of the
paper, e.g.
https://htmlpreview.github.io/?https://github.com/dcrc2cpp/destructive-move=
/blob/master/destructivemove.html
, for the reviewer's convenience. Don't make me do work in order to read
your paper! :)
(3) Have you thought about the possibility of implementing something like
your proposal via opt-in macros =C3=A1 l=C3=A0 Boost.Move? Is that remotely
conceivable?
(4)
- It should be possible to write user-defined destructive move
operations. As a particular example, if classes A and B are Relocatable,
then it should be possible to write a relocation operation for std::pair=
<A,
B>.
IMO `pair` is a bit of a poor example, because the relocation operation for
`pair` intuitively is nothing more or less than the combination of its
sub-objects' relocation operations. So `pair` would be the canonical
example of a type that doesn't need a user-defined destructive-move
operation, because the "defaulted" destructive-move operation would be
adequate.
I believe an appropriate example here would be "...if class T is
Relocatable, then it should be possible to write a relocation operation for
std::optional<T>." The relationship between T and optional<T>
preserves *trivial
relocatability* in the P1144 sense. But, if T's relocation operation is
allowed to have side effects (so that "relocating a present T" and
"relocating an absent T" have *different* effects), then the programmer
must put an `if` inside optional<T>'s destructive-move implementation.
(5)
for arguments passed by value, implementations are permitted, but not
required, to make destruction the responsibility of the callee
You might explicitly state that MSVC does do this, but Itanium ABI does not=
..
https://quuxplusone.github.io/blog/2018/11/12/parameter-lifetime-and-trivia=
l-abi/
(6)
- Moveable values are *not polymorphic*. That is, the dynamic type of
the object that a moveable value refers to is always the same as its sta=
tic
type.
- It is permitted to have a moveable value whose type is an abstract
class.
I don't immediately understand how to reconcile these two statements. It
seems like if they were both true, then it would be possible to have a
variable whose dynamic type was an abstract class type, and that should
never happen (except briefly inside constructors and destructors).
(7)
This would be valid if T has a C++11 move constructor.
Or copy constructor, surely? I believe 3.1 is slipping uncontrolledly
among the notions of "we disallow X because it would lead to
double-destructions," "we disallow X because its natural interpretation
would be inefficient =C3=A1 l=C3=A0 vector::push_front," "we allow X but yo=
u
shouldn't write it because its interpretation is inefficient," and "I
didn't even think to consider X because its natural interpretation is
inefficient."
Section 3.1 pointedly declines to consider the idea of using a *prvalue*
(e.g. the result of a function call) to initialize a moveable value, except
in the above-quoted case where it's considering and rejecting(?) the idea
of using a prvalue of the wrong type.
(8) Section 4.3, example "g4" is quite interesting.
void BAD(bool cond) {
T~ x;
if (cond) {
use(x);
} else {
use(>>x);
}
}
void GOOD(bool cond) {
T~ x;
if (cond) {
use(x);
goto done;
}
use(>>x);
done: ;
}
Here "BAD" looks like it should have the same effect as "GOOD", but in fact
"BAD" is ill-formed while "GOOD" is well-formed (according to example "g4"
in the paper). I think this quirk would not be well received.
(9)
With this definition:
- If an argument is a prvalue expression of type T, then the
corresponding template parameter will be deduced as T~, and the function
parameter will have type T~.
- If an argument is an owning reference T~, then the corresponding
template parameter will again be deduced as T~, and the function
parameter will have type T~.
- If an argument is an lvalue T&, then the corresponding template
parameter will be deduced as T&, and the function parameter will have
type T&.
- If an argument is an rvalue reference T&&, then the corresponding
template parameter will be deduced as T&&, and the function parameter
will have type T&&.
This paragraph incorrectly conflates "value category" with
"reference-type-ness." I frequently do so myself, informally, but here I
think the conflation is a bad thing. Specifically, the second bullet seems
to be implying that
T~ t;
forward_to_f(t);
would deduce parameter `x` as type `T~`, whereas I think really it should
be deduced as `T&` because `t` is still an lvalue, even though it is also
an owning reference `T~` in terms of decltype. (I mean, `decltype(t)` is
`T~`. I assume. This isn't covered explicitly anywhere AFAICT.)
(10) Section 7.3: I think you should explain why >>o.class<Base> should be
preferred over the more obvious >>o.Base.
(11) Section 9.2's `remove_range` name and signature don't make any sense
to me. Surely the Callback should be passed by plain old value (STL-style)
or by const reference (sane style), and it's the *parameter to Callback* (n=
ot
pictured in the signature) that will be passed by moveable value. Also,
this doesn't seem to have anything to do with the STL's "remove" verb. It
seems more like an "*erasing* [not *removing*] foreach".
(12) Section 9.1 seems to be the most interesting section for somebody
looking to implement `std::optional<T>::optional(optional~)`. I wouldn't
necessarily say that the current Section 7.5 is *useless*, but I do want to
see a version of Section 7.5 that shows how to implement `optional<T>`'s
relocating constructor.
HTH,
Arthur
On Sat, Feb 9, 2019 at 2:22 PM <dcrc2cpp@gmail.com> wrote:
> An updated version of this paper is now at
> https://github.com/dcrc2cpp/destructive-move
>
> The main change is that the role of "owning references" has been
> downplayed: owning reference variables have been renamed "moveable values=
",
> and they have been made more like non-reference variables. They can be
> initialized from an lvalue or rvalue reference, which was previously
> disallowed - this now calls the copy constructor or move constructor as
> appropriate, just as if a non-reference variable was being initialized.
>
> Also the behaviour of the forwarding operator has been rephrased in terms
> of changes to the scoping rules: the forwarding operator ends the scope o=
f
> the reference that it applies to. Hopefully this better explains what is
> going on: the compiler does not have to track the lifetime of objects - t=
he
> lifetime of an object is determined by the scope of the variable that
> refers to it.
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/zVg_bHmtlcU/=
unsubscribe
> .
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/91aa6796-993=
5-4a02-8021-0e35264811a0%40isocpp.org
> <https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/91aa6796-99=
35-4a02-8021-0e35264811a0%40isocpp.org?utm_medium=3Demail&utm_source=3Dfoot=
er>
> .
>
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CADvuK0LaM%2BLBuE1OqCMbDbvZBO%3Df%3DDn5z296wYV9r=
ScRvdtN_A%40mail.gmail.com.
--0000000000009bda7b05818cdb07
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div di=
r=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"lt=
r"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div=
dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr">Hi David,<div><br></div><div=
>Here's my laundry list of comments on the current draft. Nothing big h=
ere, just a lot of nitpicks. :)</div><div><br></div><div><br></div><div>(1)=
Is the README on that repo still an accurate summary of the paper's co=
ntents?</div><div><br></div><div>(2) The README should include a prominent =
link to a rendered version of the paper, e.g.=C2=A0<a href=3D"https://htmlp=
review.github.io/?https://github.com/dcrc2cpp/destructive-move/blob/master/=
destructivemove.html">https://htmlpreview.github.io/?https://github.com/dcr=
c2cpp/destructive-move/blob/master/destructivemove.html</a> , for the revie=
wer's convenience. Don't make me do work in order to read your pape=
r! :)</div><div><br></div><div>(3) Have you thought about the possibility o=
f implementing something like your proposal via opt-in macros =C3=A1 l=C3=
=A0 Boost.Move? Is that remotely conceivable?</div><div><br></div><div>(4)=
=C2=A0</div><ul style=3D"color:rgb(0,0,0);font-family:-webkit-standard"><li=
>It should be possible to write user-defined destructive move operations. A=
s a particular example, if classes=C2=A0<code>A</code>=C2=A0and=C2=A0<code>=
B</code>=C2=A0are Relocatable, then it should be possible to write a reloca=
tion operation for=C2=A0<code>std::pair<A, B></code>.</li></ul><div>I=
MO `pair` is a bit of a poor example, because the relocation operation for =
`pair` intuitively is nothing more or less than the combination of its sub-=
objects' relocation operations. So `pair` would be the canonical exampl=
e of a type that doesn't need a user-defined destructive-move operation=
, because the "defaulted" destructive-move operation would be ade=
quate.</div><div>I believe an appropriate example here would be "...if=
class T is Relocatable, then it should be possible to write a relocation o=
peration for std::optional<T>." =C2=A0The relationship between T=
and optional<T> preserves <i>trivial relocatability</i> in the P1144=
sense. But, if T's relocation operation is allowed to have side effect=
s (so that "relocating a present T" and "relocating an absen=
t T" have <i>different</i> effects), then the programmer must put an `=
if` inside optional<T>'s destructive-move implementation.</div><d=
iv><br></div><div>(5)</div><div><span style=3D"color:rgb(0,0,0);font-family=
:-webkit-standard;font-size:medium">for arguments passed by value, implemen=
tations are permitted, but not required, to make destruction the responsibi=
lity of the callee</span><br></div><div>You might explicitly state that MSV=
C does do this, but Itanium ABI does not.</div><div><a href=3D"https://quux=
plusone.github.io/blog/2018/11/12/parameter-lifetime-and-trivial-abi/">http=
s://quuxplusone.github.io/blog/2018/11/12/parameter-lifetime-and-trivial-ab=
i/</a><br></div><div><br></div><div>(6)</div><div><ul style=3D"color:rgb(0,=
0,0);font-family:-webkit-standard"><li>Moveable values are=C2=A0<em>not pol=
ymorphic</em>. That is, the dynamic type of the object that a moveable valu=
e refers to is always the same as its static type.</li><li>It is permitted =
to have a moveable value whose type is an abstract class.</li></ul></div><d=
iv>I don't immediately understand how to reconcile these two statements=
.. It seems like if they were both true, then it would be possible to have a=
variable whose dynamic type was an abstract class type, and that should ne=
ver happen (except briefly inside constructors and destructors).</div><div>=
<br></div><div>(7)</div><div><span style=3D"color:rgb(0,0,0);font-family:-w=
ebkit-standard;font-size:medium">This would be valid if=C2=A0</span><code s=
tyle=3D"color:rgb(0,0,0)">T</code><span style=3D"color:rgb(0,0,0);font-fami=
ly:-webkit-standard;font-size:medium">=C2=A0has a C++11 move constructor.</=
span><br></div><div><br></div><div>Or copy constructor, surely?=C2=A0 I bel=
ieve 3.1 is slipping uncontrolledly among the notions of "we disallow =
X because it would lead to double-destructions," "we disallow X b=
ecause its natural interpretation would be inefficient =C3=A1 l=C3=A0 vecto=
r::push_front," "we allow X but you shouldn't write it becaus=
e its interpretation is inefficient," and "I didn't even thin=
k to consider X because its natural interpretation is inefficient."</d=
iv><div>Section 3.1 pointedly declines to consider the idea of using a <i>p=
rvalue</i> (e.g. the result of a function call) to initialize a moveable va=
lue, except in the above-quoted case where it's considering and rejecti=
ng(?) the idea of using a prvalue of the wrong type.</div><div><br></div><d=
iv>(8) Section 4.3, example "g4" is quite interesting.</div><div>=
void BAD(bool cond) {</div><div>=C2=A0 =C2=A0 T~ x;</div><div>=C2=A0 =C2=A0=
if (cond) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 use(x);</div><div>=C2=A0=
=C2=A0 } else {<br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 use(>>x);<=
/div><div>=C2=A0 =C2=A0 }<br></div><div>}<br></div><div><div>void GOOD(bool=
cond) {</div><div>=C2=A0 =C2=A0 T~ x;</div><div>=C2=A0 =C2=A0 if (cond) {<=
/div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 use(x);</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 goto done;</div><div>=C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=A0 use=
(>>x);</div><div>done: ;</div><div>}</div><div>Here "BAD" l=
ooks like it should have the same effect as "GOOD", but in fact &=
quot;BAD" is ill-formed while "GOOD" is well-formed (accordi=
ng to example "g4" in the paper). I think this quirk would not be=
well received.</div></div><div><br></div><div>(9)</div><div><span style=3D=
"color:rgb(0,0,0);font-family:-webkit-standard">With this definition:</span=
><br></div><div><ul style=3D"color:rgb(0,0,0);font-family:-webkit-standard"=
><li>If an argument is a prvalue expression of type=C2=A0<code>T</code>, th=
en the corresponding template parameter will be deduced as=C2=A0<code>T~</c=
ode>, and the function parameter will have type=C2=A0<code>T~</code>.</li><=
li>If an argument is an owning reference=C2=A0<code>T~</code>, then the cor=
responding template parameter will again be deduced as=C2=A0<code>T~</code>=
, and the function parameter will have type=C2=A0<code>T~</code>.</li><li>I=
f an argument is an lvalue=C2=A0<code>T&</code>, then the corresponding=
template parameter will be deduced as=C2=A0<code>T&</code>, and the fu=
nction parameter will have type=C2=A0<code>T&</code>.</li><li>If an arg=
ument is an rvalue reference=C2=A0<code>T&&</code>, then the corres=
ponding template parameter will be deduced as=C2=A0<code>T&&</code>=
, and the function parameter will have type=C2=A0<code>T&&</code>.<=
/li></ul></div><div>This paragraph incorrectly conflates "value catego=
ry" with "reference-type-ness." I frequently do so myself, i=
nformally, but here I think the conflation is a bad thing. Specifically, th=
e second bullet seems to be implying that</div><div>=C2=A0 =C2=A0 T~ t;</di=
v><div>=C2=A0 =C2=A0 forward_to_f(t);</div><div>would deduce parameter `x` =
as type `T~`, whereas I think really it should be deduced as `T&` becau=
se `t` is still an lvalue, even though it is also an owning reference `T~` =
in terms of decltype. (I mean, `decltype(t)` is `T~`. I assume. This isn=
9;t covered explicitly anywhere AFAICT.)</div><div><br></div><div>(10) Sect=
ion 7.3: I think you should explain why=C2=A0<span style=3D"color:rgb(0,0,0=
);font-family:monospace;font-size:medium">>>o.class<Base></span=
>=C2=A0should be preferred over the more obvious=C2=A0<span style=3D"color:=
rgb(0,0,0);font-family:monospace;font-size:medium">>>o.Base</span>.</=
div><div><br></div><div>(11) Section 9.2's `remove_range` name and sign=
ature don't make any sense to me. Surely the Callback should be passed =
by plain old value (STL-style) or by const reference (sane style), and it&#=
39;s the <i>parameter to Callback</i>=C2=A0(not pictured in the signature) =
that will be passed by moveable value. Also, this doesn't seem to have =
anything to do with the STL's "remove" verb. It seems more li=
ke an "<i>erasing</i>=C2=A0[not <i>removing</i>] foreach".</div><=
div><br></div><div>(12) Section 9.1 seems to be the most interesting sectio=
n for somebody looking to implement `std::optional<T>::optional(optio=
nal~)`.=C2=A0 I wouldn't necessarily say that the current Section 7.5 i=
s <i>useless</i>, but I do want to see a version of Section 7.5 that shows =
how to implement `optional<T>`'s relocating constructor.</div><di=
v><br></div><div>HTH,</div><div>Arthur</div><div><br></div></div></div></di=
v></div></div></div></div></div></div></div></div></div></div></div></div><=
/div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">O=
n Sat, Feb 9, 2019 at 2:22 PM <<a href=3D"mailto:dcrc2cpp@gmail.com">dcr=
c2cpp@gmail.com</a>> wrote:<br></div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:so=
lid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">A=
n updated version of this paper is now at=C2=A0<a href=3D"https://github.co=
m/dcrc2cpp/destructive-move" target=3D"_blank">https://github.com/dcrc2cpp/=
destructive-move</a><div><br></div><div>The main change is that the role of=
"owning references" has been downplayed: owning reference variab=
les have been renamed "moveable values", and they have been made =
more like non-reference variables. They can be initialized from an lvalue o=
r rvalue reference, which was previously disallowed - this now calls the co=
py constructor or move constructor as appropriate, just as if a non-referen=
ce variable was being initialized.</div><div><br></div><div>Also the behavi=
our of the forwarding operator has been rephrased in terms of changes to th=
e scoping rules: the forwarding operator ends the scope of the reference th=
at it applies to. Hopefully this better explains what is going on: the comp=
iler does not have to track the lifetime of objects - the lifetime of an ob=
ject is determined by the scope of the variable that refers to it.</div></d=
iv>
<p></p>
-- <br>
You received this message because you are subscribed to a topic in the Goog=
le Groups "ISO C++ Standard - Future Proposals" group.<br>
To unsubscribe from this topic, visit <a href=3D"https://groups.google.com/=
a/isocpp.org/d/topic/std-proposals/zVg_bHmtlcU/unsubscribe" target=3D"_blan=
k">https://groups.google.com/a/isocpp.org/d/topic/std-proposals/zVg_bHmtlcU=
/unsubscribe</a>.<br>
To unsubscribe from this group and all its topics, send an email to <a href=
=3D"mailto:std-proposals+unsubscribe@isocpp.org" target=3D"_blank">std-prop=
osals+unsubscribe@isocpp.org</a>.<br>
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org" target=3D"_blank">std-proposals@isocpp.org</a>.<br>
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/91aa6796-9935-4a02-8021-0e35264811a0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter" target=3D"_blank">=
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/91aa6796-9935-=
4a02-8021-0e35264811a0%40isocpp.org</a>.<br>
</blockquote></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CADvuK0LaM%2BLBuE1OqCMbDbvZBO%3Df%3DD=
n5z296wYV9rScRvdtN_A%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0LaM%=
2BLBuE1OqCMbDbvZBO%3Df%3DDn5z296wYV9rScRvdtN_A%40mail.gmail.com</a>.<br />
--0000000000009bda7b05818cdb07--
.
Author: David Collier <dcrc2cpp@gmail.com>
Date: Mon, 11 Feb 2019 15:41:49 +0000
Raw View
--0000000000005448c30581a02637
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Thanks again Arthur. Some responses below. For your remaining points,
basically I think you're right and I'll try to rewrite those parts
accordingly.
On Sun, Feb 10, 2019 at 4:41 PM Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
wrote:
> (3) Have you thought about the possibility of implementing something like
> your proposal via opt-in macros =C3=A1 l=C3=A0 Boost.Move? Is that remote=
ly
> conceivable?
>
I'd not given this serious thought before, but actually, it seems like it
would work to some extent. You could have an owning_reference class
template, with a way to initialize it via a macro (I don't see any other
way for it to correctly bind to a temporary). I don't think overload
resolution could work as intended for owning_reference lvalues, but perhaps
that's not a disaster. The main thing you'd lose would be compile-time
safety: if you used a variable after it had been moved from you'd get a
runtime rather than a compile-time error. And the library might be prone to
creating dangling references if used incorrectly. I also don't see any way
to do destructuring without resorting to UB. Because of these things, I'm
not sure anyone would actually want to *use* such a library, but it might
be useful to implement it to demonstrate the idea.
> (6)
>
> - Moveable values are *not polymorphic*. That is, the dynamic type of
> the object that a moveable value refers to is always the same as its s=
tatic
> type.
> - It is permitted to have a moveable value whose type is an abstract
> class.
>
> I don't immediately understand how to reconcile these two statements. It
> seems like if they were both true, then it would be possible to have a
> variable whose dynamic type was an abstract class type, and that should
> never happen (except briefly inside constructors and destructors).
>
These really are variables whose dynamic type is an abstract class type. I
think I've missed out an important point here: the only way you can create
a moveable value of an abstract class type is by destructuring an object of
some derived type. So when you say they exist "briefly inside ...
destructors", that basically *is* what's going on here.
> (8) Section 4.3, example "g4" is quite interesting.
> void BAD(bool cond) {
> T~ x;
> if (cond) {
> use(x);
> } else {
> use(>>x);
> }
> }
> void GOOD(bool cond) {
> T~ x;
> if (cond) {
> use(x);
> goto done;
> }
> use(>>x);
> done: ;
> }
> Here "BAD" looks like it should have the same effect as "GOOD", but in
> fact "BAD" is ill-formed while "GOOD" is well-formed (according to exampl=
e
> "g4" in the paper). I think this quirk would not be well received.
>
You could rewrite BAD as
void BETTER(bool cond) {
if (T~ x; cond) {
use(x);
} else {
use(>>x);
}
}
I do agree that it would be unfortunate if the rules somehow encouraged use
of goto. But the behaviour of GOOD is well-defined so I don't really see
any reason to disallow it, unless you deliberately want to hobble goto
statements. To be honest I'd have expected that the whole idea of an
operator which ends the scope of a variable would lead to several
over-my-dead-body objections, so I'd happily concede the relatively minor
point about gotos if that would make anyone happy :)
--=20
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 e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAB55TMqNbL6n9DtOt8E%2Bzw4yh9h96afX3tODWdTLq3MFW=
8LHnA%40mail.gmail.com.
--0000000000005448c30581a02637
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr">Thanks again Arthur. Som=
e responses below. For your remaining points, basically I think you're =
right and I'll try to rewrite those parts accordingly.</div></div><br><=
div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun, Feb=
10, 2019 at 4:41 PM Arthur O'Dwyer <<a href=3D"mailto:arthur.j.odwy=
er@gmail.com">arthur.j.odwyer@gmail.com</a>> wrote:</div><blockquote cla=
ss=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid =
rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div dir=3D"ltr"><div d=
ir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"l=
tr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><di=
v dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=
=3D"ltr"><div>(3) Have you thought about the possibility of implementing so=
mething like your proposal via opt-in macros =C3=A1 l=C3=A0 Boost.Move? Is =
that remotely conceivable?</div></div></div></div></div></div></div></div><=
/div></div></div></div></div></div></div></div></div></blockquote><div><br>=
</div><div>I'd not given this serious thought before, but actually, it =
seems like it would work to some extent. You could have an owning_reference=
class template, with a way to initialize it via a macro (I don't see a=
ny other way for it to correctly bind to a temporary). I don't think ov=
erload resolution could work as intended for owning_reference lvalues, but =
perhaps that's not a disaster. The main thing you'd lose would be c=
ompile-time safety: if you used a variable after it had been moved from you=
'd get a runtime rather than a compile-time error. And the library migh=
t be prone to creating dangling references if used incorrectly. I also don&=
#39;t see any way to do destructuring without resorting to UB. Because of t=
hese things, I'm not sure anyone would actually want to *use* such a li=
brary, but it might be useful to implement it to demonstrate the idea.</div=
><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px=
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div di=
r=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"lt=
r"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div=
dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D=
"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div>(6)</div><div><ul style=3D"col=
or:rgb(0,0,0);font-family:-webkit-standard"><li>Moveable values are=C2=A0<e=
m>not polymorphic</em>. That is, the dynamic type of the object that a move=
able value refers to is always the same as its static type.</li><li>It is p=
ermitted to have a moveable value whose type is an abstract class.</li></ul=
></div><div>I don't immediately understand how to reconcile these two s=
tatements. It seems like if they were both true, then it would be possible =
to have a variable whose dynamic type was an abstract class type, and that =
should never happen (except briefly inside constructors and destructors).</=
div></div></div></div></div></div></div></div></div></div></div></div></div=
></div></div></div></div></blockquote><div><br></div><div>These really are =
variables whose dynamic type is an abstract class type. I think I've mi=
ssed out an important point here: the only way you can create a moveable va=
lue of an abstract class type is by destructuring an object of some derived=
type. So when you say they exist "briefly inside ... destructors"=
;, that basically *is* what's going on here.</div><div><br></div><div>=
=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0=
..8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"l=
tr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><di=
v dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=
=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr=
"><div dir=3D"ltr"><div dir=3D"ltr"><div>(8) Section 4.3, example "g4&=
quot; is quite interesting.</div><div>void BAD(bool cond) {</div><div>=C2=
=A0 =C2=A0 T~ x;</div><div>=C2=A0 =C2=A0 if (cond) {</div><div>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 use(x);</div><div>=C2=A0 =C2=A0 } else {<br></div><div>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 use(>>x);</div><div>=C2=A0 =C2=A0 }<br></=
div><div>}<br></div><div><div>void GOOD(bool cond) {</div><div>=C2=A0 =C2=
=A0 T~ x;</div><div>=C2=A0 =C2=A0 if (cond) {</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 use(x);</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 goto done;</div><d=
iv>=C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=A0 use(>>x);</div><div>done: =
;</div><div>}</div><div>Here "BAD" looks like it should have the =
same effect as "GOOD", but in fact "BAD" is ill-formed =
while "GOOD" is well-formed (according to example "g4" =
in the paper). I think this quirk would not be well received.</div></div></=
div></div></div></div></div></div></div></div></div></div></div></div></div=
></div></div></div></blockquote><div><br></div><div>=C2=A0You could rewrite=
BAD as</div><div><br></div><div>void BETTER(bool cond) {</div><div>=C2=A0 =
=C2=A0 if (T~ x; cond) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 use(x);</div=
><div>=C2=A0 =C2=A0 } else {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 use(>=
>x);</div><div>=C2=A0 =C2=A0 }</div><div>}</div><div><br></div><div>I do=
agree that it would be unfortunate if the rules somehow encouraged use of =
goto. But the behaviour of GOOD is well-defined so I don't really see a=
ny reason to disallow it, unless you deliberately want to hobble goto state=
ments. To be honest I'd have expected that the whole idea of an operato=
r which ends the scope of a variable would lead to several over-my-dead-bod=
y objections, so I'd happily concede the relatively minor point about g=
otos if that would make anyone happy :)</div></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CAB55TMqNbL6n9DtOt8E%2Bzw4yh9h96afX3t=
ODWdTLq3MFW8LHnA%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAB55TMqNbL6n9D=
tOt8E%2Bzw4yh9h96afX3tODWdTLq3MFW8LHnA%40mail.gmail.com</a>.<br />
--0000000000005448c30581a02637--
.