Move semantics for D

Benjamin Thaut code at benjamin-thaut.de
Fri Jul 13 01:44:16 PDT 2012


Am 13.07.2012 10:06, schrieb monarch_dodra:
> On Friday, 13 July 2012 at 06:50:02 UTC, Benjamin Thaut wrote:
>> Move semantics in C++0x are quite nice for optimization purposes.
>> Thinking about it, it should be fairly easy to implement move
>> semantics in D as structs don't have identity. Therefor a move
>> constructor would not be required. You can already move value types
>> for example within an array just by plain moving the data of the value
>> around. With a little new keyword 'mov' or 'move' it would also be
>> possible to move value types into and out of functions, something like
>> this:
>>
>> mov Range findNext(mov Range r)
>> {
>>   //do stuff here
>> }
>>
>> With something like this it would not be neccessary to copy the range
>> twice during the call of this function, the compiler could just plain
>> copy the data and reinitialize the origin in case of the argument.
>> In case of the return value to only copying would be neccessary as the
>> data goes out of scope anyway.
>>
>> The only question would be if this causes any problems with out
>> contracts.
>>
>> The pre C++0x move trick, reserving a bit in the value representation
>> for marking that the next copy is a move, is unfortunately not
>> possible D because D does not have a copy constructor.
>>
>> I for example have a range that iterates over a octree and thus needs
>> to internally track which nodes it already visited and which ones are
>> still left. This is done with a stack container. That needs to be
>> copied everytime the range is copied, which causes quite some overhead.
>>
>> Kind Regards
>> Benjamin Thaut
>
> I'm pretty sure D already has it: Values types are "moved" in and out of
> function, implicitly, when possible, without any special semantics.
>
> For "return by value", the value is simply "blit copied" (memcopy), when
> returning a local variable. Neither the source constructor is called,
> nor the target postblit constructor. Just binary bit copy.
>
> For passing in by value, the compiler will do the same trick "if and
> when" it can detect you are never going to use said value again. If you
> are, you can always force a move using an explicit std.algorithm.move:
> "myRange = findNext(move(myRange));"
>
> You get pretty the same effect as in C++11, except:
> a) the compiler will eagerly move stuff for you
> b) you don't even have to define fun(T&&) (Whew)
>
> Finally, if you want to remove the responsibility of the move from the
> caller to the callee, I *guess* you can always just pass by ref and do
> stuff there:
>
> Range findNext(ref Range r)
> {
>     auto r2;
>     move(r, r2); //move r into r2
>     //do stuff here
>     return r2; //move return
> }
>
> Note that while it might seem useless to move r into r2 (since you
> already have r by reference), you still have to move into a local
> temporary so that the compiler can "move" r2 out of findNext. The above
> function will make 0 calls to this(this) and 0 calls to ~this. There
> will be about two copies of this.init.
>
> ...of course, at this point, one could wonder why:
> a) you don't just take a ref, and return void?
> b) Use the safer just as efficient "myRange = findNext(move(myRange));"

I didn't know know about the compiler already moving structs as return 
values. But not having to do the move for a argument manuall would be 
nice, espeically as ref does not work with non-lvalues

Kind Regards
Benjamin Thaut



More information about the Digitalmars-d mailing list