D's equivalent to C++'s std::move?
Lars T. Kyllingstad via Digitalmars-d
digitalmars-d at puremagic.com
Sat Feb 13 13:41:06 PST 2016
On Saturday, 13 February 2016 at 19:25:37 UTC, Ola Fosheim
Grøstad wrote:
> On Saturday, 13 February 2016 at 17:47:54 UTC, Lars T.
> Kyllingstad wrote:
>> [...]
>
> C++ does indeed put the burden on the library programmer and is
> not a good language for "non-professional" use. But it is
> flexible by providing the mechanisms in the type system rather
> than an opinionated solution. [...]
D is all about opinionated solutions. :) In fact, I would go so
far as to say that's what sets D apart from C++, and mostly in a
good way.
> [...]
>
>> Here, you have unnecessary construction of C's members in the
>> constructor which may or may not be optimised away before the
>> assignment.
>
> Well, doing a swap would break the expectations for
> assignment...
Whose expectations? The formal expectation, as per the C++
standard, is that the moved-from object be left in a "valid but
unspecified state". Basically, as long as it is safe to destroy
or reassign to the moved-from object, you're good.
I hope this is not coming across as me endorsing the practice of
implementing move assignment in terms of swap, because I don't.
But it *is* a rather common practice, enough so that Scott Meyers
felt the need to write an article about it:
http://scottmeyers.blogspot.no/2014/06/the-drawbacks-of-implementing-move.html
>> Furthermore, you have an unnecessary number of moves in the
>> assignment operator -- plus the potential drawbacks of
>> deferred release of the resource.
>
> I don't understand what you mean by unnecessary moves?
> std::move/std::forward are just type casting so they don't
> result in code...
A swap is three moves -- actual moves.
>> I'm not sure what you mean by "has move semantics" here. It
>> does not have C++'s move semantics, no, but I would say D has
>> its own move semantics. It has a move() function that
>> transfers raw state between objects, and D structs are
>> supposed to be designed so they are movable by means of raw
>> bit transfer, allowing the compiler and GC to move them around
>> as it sees fit. But maybe I'm missing something?
>
> Well, but that is like saying that C++03 also had move
> semantics. There is nothing special about D's move(), it's just
> a library function?
What is special is D's requirement that structs be movable by a
raw bit blit, which again enables our particular library
implementation of move().
C++ has no such requirement; for example it is perfectly OK for
an on-stack C++ object to contain a pointer to itself. A D-like
move() on such an object would just produce mayhem.
>>> No? With D's std.move() the resource can be destroyed or get
>>> into an inconsistent state if the caller does it wrong?
>>
>> I guess this is what I don't understand. How and when does
>> that happen?
>
> The std.move() actually does a copy, then copy the init value
> to the original. If something happens that prevents the value
> from being preserved the object will be destroyed by the
> destructors. I.e. an exception.
If you are still talking about this case:
fun(move(someResource));
where fun() throws, like Sönke I don't have a big problem with
the resource being lost there. Given D's semantics, this is what
I would expect. And in D, at least you *know* it is lost, and it
is easy to understand and explain to users. In C++ you have no
idea whether the resource is lost -- it depends on when the
actual move operation happens and when the exception is thrown.
> And worse, if you have back pointers to it, it will end up
> being inconsistent. There is no way the type system can prevent
> back pointers without preventing D from being usable as a
> language. Since you no longer have the original object... shit
> can happen. In C++ you can set a mutex in the object and fix
> things because you have the full object. So if someone tries to
> follow the back pointer the mutex will block. You can probably
> come up with many other scenarios. "postblit" does not fix this
> (not a very elegant solution IMO).
Still not following you. Postblit is not involved in a move at
all -- that's what makes it a move.
If an exception is thrown, the object's destructor is called, and
it would be the destructor's responsibility to break all ties to
other objects.
> [...]
More information about the Digitalmars-d
mailing list