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