www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - D move semantics

reply piotrekg2 <piotrekg2 gmail.com> writes:
What is the idiomatic D code equivalent to this c++ code?

class Block
{
public:
   Block()
     : data_(new char[4096])
   {}

   ...

   // NOTE: both members marked noexcept
   Block(Block &&rhs) noexcept = default;
   Block& operator=(Block &&rhs) noexcept = default;

   ...

private:
   std::unique_ptr<char> data_;
};

// What is the equivalent of std::vector, the closest thing I 
could find is
// std.container.array
std::vector<Block> blocks;

for (int i = 0; i < 100; ++i) {
   // NOTE: blocks are moved when relocation happens
   // because of move-ctor and move-assign-operator marked noexcept
   blocks.emplace_back();
}
Jul 30 2017
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 30 July 2017 at 16:12:41 UTC, piotrekg2 wrote:
 What is the idiomatic D code equivalent to this c++ code?
There's no direct equivalent of all your code to D using only druntime+phobos AFAIK.
 class Block
 {
 [...]
 };
Since you don't seem to be using reference type semantics or polymorphism this should be mapped to a struct, such as --- import std.experimental.allocator; import std.experimental.allocator.mallocator; struct Block { public: static Block create() { Block obj; obj.data_ = Mallocator.instance.makeArray!char(4096); return obj; } ~this() nothrow { if (data_ !is null) { Mallocator.instance.dispose(data_); data_ = null; } } disable this(this); // Forbid copying private: char[] data_; } ---
 // What is the equivalent of std::vector, the closest thing I 
 could find is
 // std.container.array
 std::vector<Block> blocks;

 for (int i = 0; i < 100; ++i) {
   // NOTE: blocks are moved when relocation happens
   // because of move-ctor and move-assign-operator marked 
 noexcept
   blocks.emplace_back();
 }
That's the closest one in Phobos AFAIK. There are custom container implementations out there such as the emsi containers [1]. If you use one of them, the above should be as simple as --- Array!Block blocks; foreach (i; 0..100) { blocks ~= Block.create(); } --- I've added your example as a unittest to my own dynamic array implementation, should you wish to have a look [2]. A little bit of background: Classes are reference types, structs are value types i.e there's no copy/move mechanics for classes w.r.t. your code. The one for structs is roughly like this: Whenever the compiler sees a struct object `obj` being assigned a new value `other`, it will run the destructor for `obj` (should one exist), then copy `other` over `obj`, followed by calling the postblit constructor `this(this) { ... }` (should it exist) on `obj`. In some instances (such as return from function, or first assignment in constructor, i.e. initialization) the compiler may automatically optimize the copy to a move. Assuming the compiler tries to do a copy, it will only work if `typeof(obj)` is copyable (doesn't have the postblit disabled via ` disable this(this)`), if it isn't, the compiler will error out; you can force a move by using `std.algorithm : move`. There's also `std.algorithm : moveEmplace` in case you don't wish the target to be destroyed. [1] https://github.com/economicmodeling/containers [2] https://github.com/Calrama/libds/blob/83211c5d7cb866a942dc9dd8ba1c622573611ccd/src/ds/dynamicarray.d#L351
Jul 30 2017