Discussion: Rvalue refs and a Move construtor for D

Manu turkeyman at gmail.com
Wed Sep 4 20:23:14 UTC 2019


On Wed, Sep 4, 2019 at 12:05 PM kinke via Digitalmars-d
<digitalmars-d at puremagic.com> wrote:
>
> On Wednesday, 4 September 2019 at 18:43:08 UTC, Manu wrote:
> > On Wed, Sep 4, 2019 at 7:50 AM Suleyman via Digitalmars-d
> > <digitalmars-d at puremagic.com> wrote:
> >>
> >> On Wednesday, 4 September 2019 at 00:58:44 UTC, Manu wrote:
> >> > Move semantics aren't a feature of the move constructor, they
> >> > are USED
> >> > BY the move constructor.
> >> > You can move an argument to any function. Consider a
> >> > unique_ptr, which
> >> > can only move. It would be impossible to pass a unique_ptr to
> >> > any
> >> > other function than the move constructor itself.
> >>
> >> If you can get the move constructor and move assignment in
> >> addition to an intrinsic function for moving lvalues to
> >> rvalues then you can do move semantics without rvalue ref.
> >>
> >> unique_ptr in C++ doesn't move itself magically. You have to
> >> eplicitly move it by calling `move()`. Example:
> >> https://cpp.godbolt.org/z/8jVONg.
> >> You can do that with the machinery provided in the POC without
> >> rvalue ref.
> >
> > You misunderstood what I'm saying.
> > I'm saying that it can't only be a `@move` constructor that can
> > accept
> > rval references, any argument should be able to be one.
> > Functions may
> > have multiple arguments, and some of them may be unique_ptr-like
> > objects.
> > If you accept by-value, and you use a move-constructor to
> > construct
> > the argument, then we're back at making a copy at every level
> > of the
> > callstack, and that's specifically what we need to avoid.
>
> Nope, Suleyman is totally right here. Move constructors are in
> fact never ever used to construct a parameter from an argument.
> The only time a move ctor is called is for `auto var =
> std::move(otherVar)`. That's how C++ handles it, and that's how
> an improved D could handle it as well, without rvalue refs in the
> language.
>
> // high-level: by value
> // low-level: just gets 2 pointers to temporaries and directly
> manipulates those,
> //            no copying or moving at all
> void func(T)(UniquePtr!T a, UniquePtr!T b);
>
> void foo(T)(UniquePtr!T a) // again, `a` is a ref to a temporary
> {
>      // forward the `a` ref; construct a new UniquePtr and forward
> its address
>      func(move(a), makeUnique!T());
> }
>
> void bar(T)()
> {
>      // Construct a new UniquePtr and forward its address to `foo`.
>      // In the end, manipulating `a` in `func` will manipulate
> this temporary here, across 2 calls.
>      foo(makeUnique!T());
> }
>
> For this to work, UniquePtr wouldn't need a move ctor. This is
> just an ABI detail (and requires a `move` intrinsic, as stated
> multiple times already).

No you've misunderstood me again.
Your examples above show functions receiving arguments by value...
That's not even on discussion here (is it? if it is, then we're having
different conversations).
Those arguments will be copied (via move or otherwise) to the argument
values before the calls... but that's not moving something into the
call, that's just move-copying an argument.
If those functions called another function, they would just continue
the copy-chain down the stack.


More information about the Digitalmars-d mailing list