A problem of "value types" with external resources (like std::vector<T>
or std::string
) is that copying them tends to be quite expensive, and copies are created implicitly in various contexts, so this tends to be a performance concern. C++0x's answer to this problem is move semantics, which is conceptionally based on the idea of resource pilfering and technically powered by rvalue references.
Does D have anything similar to move semantics or rvalue references?
I believe that there are several places in D (such as returning structs) that D manages to make them moves whereas C++ would make them a copy. IIRC, the compiler will do a move rather than a copy in any case where it can determine that a copy isn't needed, so struct copying is going to happen less in D than in C++. And of course, since classes are references, they don't have the problem at all.
But regardless, copy construction already works differently in D than in C++. Generally, instead of declaring a copy constructor, you declare a postblit constructor: this(this)
. It does a full memcpy before this(this)
is called, and you only make whatever changes are necessary to ensure that the new struct is separate from the original (such as doing a deep copy of member variables where needed), as opposed to creating an entirely new constructor that must copy everything. So, the general approach is already a bit different from C++. It's also generally agreed upon that structs should not have expensive postblit constructors - copying structs should be cheap - so it's less of an issue than it would be in C++. Objects which would be expensive to copy are generally either classes or structs with reference or COW semantics.
Containers are generally reference types (in Phobos, they're structs rather than classes, since they don't need polymorphism, but copying them does not copy their contents, so they're still reference types), so copying them around is not expensive like it would be in C++.
There may very well be cases in D where it could use something similar to a move constructor, but in general, D has been designed in such a way as to reduce the problems that C++ has with copying objects around, so it's nowhere near the problem that it is in C++.
I think all answers completely failed to answer the original question.
First, as stated above, the question is only relevant for structs. Classes have no meaningful move. Also stated above, for structs, a certain amount of move will happen automatically by the compiler under certain conditions.
If you wish to get control over the move operations, here's what you have to do. You can disable copying by annotating this(this) with @disable. Next, you can override C++'s constructor(constructor &&that)
by defining this(Struct that)
. Likewise, you can override the assign with opAssign(Struct that)
. In both cases, you need to make sure that you destroy the values of that
.
For assignment, since you also need to destroy the old value of this
, the simplest way is to swap them. An implementation of C++'s unique_ptr
would, therefore, look something like this:
struct UniquePtr(T) { private T* ptr = null; @disable this(this); // This disables both copy construction and opAssign // The obvious constructor, destructor and accessor this(T* ptr) { if(ptr !is null) this.ptr = ptr; } ~this() { freeMemory(ptr); } inout(T)* get() inout { return ptr; } // Move operations this(UniquePtr!T that) { this.ptr = that.ptr; that.ptr = null; } ref UniquePtr!T opAssign(UniquePtr!T that) { // Notice no "ref" on "that" swap(this.ptr, that.ptr); // We change it anyways, because it's a temporary return this; } }
Edit: Notice I did not define opAssign(ref UniquePtr!T that)
. That is the copy assignment operator, and if you try to define it, the compiler will error out because you declared, in the @disable
line, that you have no such thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With