On Saturday, 13 February 2016 at 21:41:06 UTC, Lars T. Kyllingstad wrote:
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.

D1 was all about opinionated ready-made builtin solutions, but D2 is supposedly meant to support generic programming and then the responsibility of "creating opinions" should be moved out of the language and into libraries.


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.

Hmm, do you have a reference (URL) to the "valid but unspecified state" part? I'm not quite sure what that refers to.


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:

I've never heard of it, and never thought it would be a good idea. Are you sure this is common?


A swap is three moves -- actual moves.

If you are talking std::swap, probably. Never use it, so don't know if there is any measurable overhead.

If you are talking about the microcode in the CPU, then it typically takes 2 loads and 2 stores to swap two pointers on the heap, and the loads and stores can execute in parallel... So performance wise, not a big deal. But with debugging/consistency in mind you should set the source to nullptr instead.

I know programmers talk alot about swap being implemented as

tmp = a
a = b
b = a

But that is actually how it is specified it source code, not how it is implemented in running code. In the CPU it goes like this:

reg1 = load a; reg2 = load b
b = store reg1; a = store reg2

Setting it to null would be almost the same.

reg1 = load a; reg2 = 0
b = store reg1; a = store reg2

Unless you use special commands and zero out the entire cacheline of "a" you still get the same amount of cache-misses as well.


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.

Yes, but it isn't enforced by the compiler by static analysis, is it? So D has no particular advantage to C++ for an object that is designed to be movable.


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.

Well, you do, if you implement exception safe RAII, which you should. RAII ensures that it will be released when the owner object is destructed.


Still not following you. Postblit is not involved in a move at all -- that's what makes it a move.

Well, if you have a back pointer that is part of the invariant for the type, then neither move or copy work as expected. In C++ you have the address of the source object and can either modify or change the associated data-structure that provide back pointers (e.g. a global hash with pointers to the struct, in C++ you can change these pointers to point to the new location/add another entry). AFAIK this is not possible in D without adding an indirection.


Reply via email to