On Friday, April 29, 2016 at 2:15:03 PM UTC+10, Jim Blandy wrote:
> On Thu, Apr 28, 2016 at 8:22 PM, <jw...@mozilla.com> wrote:
> 
> > Jim Blandy於 2016年4月28日星期四 UTC+8下午1時51分15秒寫道:
> > > I don't really think it's a good example. TakeMediaIfKnown is accepting a
> > > UniquePtr<MediaFile> as an inout parameter: it uses, and may modify, its
> > > value. It should take UniquePtr<MediaFile> &.
> > IIUC, UniquePtr<T> can't be an inout parameter for its unique semantics
> > which owns sole ownership of an object. The caller won't be able to use the
> > object in a meaningful way after the function returns.
> >
> >
> >
> I'm not sure I understand. Maybe it would help if we had a more concrete
> example to talk about:
> 
> $ cat unique-inout.cc
> #include <stdio.h>
> #include "mozilla/UniquePtr.h"
> 
> using mozilla::UniquePtr;
> 
> struct MediaFile {
>   const char *name;
>   MediaFile(const char *name) : name(name) { printf("constructing %s\n",
> name); }
>   ~MediaFile() { printf("destructing %s\n", name); }
> };
> 
> int foo(UniquePtr<MediaFile> &arg, bool pleaseSwap)
> {
>   if (pleaseSwap) {
>     UniquePtr<MediaFile> ptr = Move(arg);
>     arg = UniquePtr<MediaFile>(new MediaFile("foo's"));
>   }
> }
> 
> int main(int argc, char **argv) {
>   UniquePtr<MediaFile> first(new MediaFile("first"));
>   printf("before first call\n");
>   foo(first, false);
>   printf("after first call\n");
> 
>   UniquePtr<MediaFile> second(new MediaFile("second"));
>   printf("before second call\n");
>   foo(second, true);
>   printf("after second call\n");
> 
> }
> $ ln -sf /home/jimb/moz/dbg/mfbt mozilla
> $ g++ -std=c++11 -I . unique-inout.cc -o unique-inout
> $ ./unique-inout
> constructing first
> before first call
> after first call
> constructing second
> before second call
> constructing foo's
> destructing second
> after second call
> destructing foo's
> destructing first
> $
> 
> The first MediaFile's destructor doesn't run until the end of main. The
> second MediaFile's destructor runs during the second call to foo, and then
> foo's MedialFile's destructor runs at the end of main.
> 
> That's what I meant by a function taking a UniquePtr as an inout parameter.
> It seemed to me like the function Gerald imagined should be written as in
> my code above, rather than passing Move(...) as the argument.

I guess my example was not that convincing. :-P

What about a function that takes T&, but then wants to "steal" the contents of 
T? (Say, to emplace it into an array.)
The most efficient way is to Move() it to a 2nd function that takes T&&. But it 
means that the first-level function will now have a shell of that object that 
was passed as an lvalue ref, so maybe its caller will still use that object 
somehow.
(Once again, just thinking of the possibilities, maybe there's no actual need 
for that pattern in real life.)
For example, we know how strings behave when moved from* (the original becomes 
empty), and it'd be nice to be able to use that trick when possible and really 
needed.

If we want to discourage that as well, I guess we'd need to enforce another 
restriction, e.g. "you cannot Move() an lvalue reference".

> Although the
> language doesn't enforce it, I think Move should be reserved for
> unconditional transfers of ownership.

And I say: Yes, let's agree that Move() *will* be reserved for unconditional 
transfers.
But please allow for an escape hatch, e.g. 'MakeAvailableForMove/MaybeMove'** 
or similar, just in case.


* Regarding the validity of moved-from objects:
I can think of 3 categories:
1. Objects that survive being moved-from, and are totally reusable, with the 
default behavior of just being empty -- whatever that means in each case, e.g. 
containers&strings become empty, pointers become null, etc.
2. Objects that should only be assigned-to through operator=(), e.g. physical 
resource handlers.
3. Objects that shouldn't be touched at all (except destruction).
(And maybe objects that are semi-functional, e.g. you can use some methods but 
not others; This seems too hard to reason with anyway, so let's not go there.)

It'd be nice to discuss whether we could&should auto-classify all our types 
into one default group (looks like we're going for '3' here) and allow 
annotations to move some to other groups; Move semantics could then be tailored 
by types.


** Tangent:
It'd be nice to be able to mark some things as 
'MOZ_ARE_YOU_SURE_YOU_WANT_TO_USE_THIS', and ReviewBoard would make them very 
obvious, to ensure extra attention during reviews.
Or require review from a chosen few (similar to dom peers having to review dom 
changes).
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to