Discussion Thread: DIP 1040--Copying, Moving, and Forwarding--Community Review Round 1
tsbockman
thomas.bockman at gmail.com
Fri Mar 12 06:52:09 UTC 2021
On Friday, 12 March 2021 at 01:43:01 UTC, tsbockman wrote:
> On Friday, 12 March 2021 at 01:40:22 UTC, tsbockman wrote:
>> I think I finally figure out how to make some sense out of the
>> DIP's description. However, the lowering cannot be expressed
>> clearly with the DIP's syntax, so I will use an alternative
>> notation:
>>
>> void moveConstruct(ref S source) nothrow @nogc {
>> if(source.isUnique) {
>> ptr = &internal;
>> internal = source.internal;
>> } else
>> ptr = source.ptr;
>> }
>> void moveAssign(ref S source) @trusted nothrow @nogc {
>> S oldDest = void;
>> oldDest.moveConstruct(this); // Move the old value to a
>> temporary.
>> moveConstruct(source);
>> // Implicitly destroy the old value.
>> }
>>
>> Is this correct?
Nope, still not correct. I had a bug in the surrounding context,
and wasn't testing enough things. Here's another attempt that
passes a more thorough test:
https://gist.github.com/run-dlang/b789714c01905f091a44ee2666276433
The important bit:
/* move construction and assignment (these must be called manually
and do not use the DIP syntax, since it's not implemented yet): */
void moveConstruct(ref S source) @system nothrow @nogc {
// @system since this must not be called by itself on an
already-initialized object.
if(source.isUnique) {
ptr = &internal;
internal = source.internal;
} else
ptr = source.ptr;
source.ptr = null;
}
void moveAssign(ref S source) @trusted nothrow @nogc {
static if(useDIPLowering) {
// destroy after (the DIP's proposal):
S newVal = void;
newVal.moveConstruct(source);
S oldVal = void;
oldVal.moveConstruct(this);
moveConstruct(newVal);
// Implicitly destruct(oldVal).
} else {
// conditionally move and destroy before (my proposal):
if(&source !is &this) {
destruct(this);
moveConstruct(source);
}
}
}
Key changes: the move constructor must put the source into a
state where the destructor is a no-op, and for the move
assignment operation to destroy the old value *after* the move,
as required by the DIP, TWO extra moves are required. That is a
lot of extra work and confusion just to avoid explicitly checking
if the source and destination are the same. This seems especially
silly given that the optimizer can probably detect the
move-to-self case at compile time in many cases, and eliminate
either the test, or the entire move during compilation.
Is there some other motivation for destroying after, rather than
before, besides the self-move case?
More information about the Digitalmars-d
mailing list