Discussion: Rvalue refs and a Move construtor for D
kinke
noone at nowhere.com
Thu Aug 29 20:26:10 UTC 2019
On Thursday, 29 August 2019 at 19:04:45 UTC, Manu wrote:
> Our move semantics are slow (lots of copying
I fully agree and it's been bothering me for years too.
C++:
void callee(NoPOD s);
/* Low-level, this is actually `void callee(NoPOD &&s)`.
* The caller is to allocate & set up the instance before the
call,
* pass a pointer to it and then destruct it after the call.
*/
void caller()
{
// rvalue case:
callee(NoPOD());
/* actually:
{
NoPOD temp;
callee((NoPOD &&) &temp);
} // destruct temp
*/
// lvalue case:
NoPOD lvalueArg;
callee(lvalueArg);
/* actually:
{
NoPOD temp = lvalueArg; // full copy
callee((NoPOD &&) &temp);
} // destruct temp
*/
// manual moving:
callee(std::move(lvalueArg));
/* actually:
callee((NoPOD &&) &lvalueArg);
*/
}
D:
If we adopted the C++ ABI in this regard (avoid the stack for
non-PODs, possibly for large PODs too, and use rvalue refs under
the hood) and made `move` an intrinsic, the compiler could use it
to elide the lvalue copy for arguments passed by value.
Similary, if `forward` was an intrinsic, the compiler could use
it to propagate the lvalue-ness of `auto ref` parameters as
arguments:
void callee(ref NoPOD s); // for lvalues
void callee(NoPOD s); // for rvalues, actually: `@rvalue ref
NoPOD s`
void wrapper()(auto ref NoPOD s)
{
callee(forward(s));
/* actually:
static if (__traits(isRef, s)) // void wrapper(ref NoPOD s)
{
// call lvalue overload, perfectly forwarding the `s`
reference
callee(s);
}
else // void wrapper(@rvalue ref NoPOD s)
{
// call rvalue overload, perfectly forwarding the `s`
rvalue reference
callee(s);
}
}
void caller()
{
// rvalue case:
wrapper(NoPOD());
/* actually:
{
NoPOD temp;
wrapper(cast(@rvalue ref) temp); // just forwards the
pointer to rvalue-version of callee
} // destruct temp
*/
// lvalue case:
NoPOD lvalueArg;
wrapper(lvalueArg); // just forwards the pointer to
lvalue-version of callee
// manual moving:
wrapper(move(lvalueArg));
/* actually:
wrapper(cast(@rvalue ref) lvalueArg); // forwards the pointer
to rvalue-version of callee
*/
}
I hope that covers enough use cases, so that we could get away
with ABI change (which btw would also fix C++ interop wrt.
passing non-PODs by value) + move/forward as intrinsics, without
having to touch the language and introducing ugly `@rvalue ref`.
More information about the Digitalmars-d
mailing list