I have already asked a similar question a while ago, but I\'m still unclear on some details.
Under what circumstances is the postblit constructor called?
A postblit constructor is called whenever the struct is copied - e.g. when passing a struct to a function.
A move is a bitwise copy. The postblit constructor is never called. The destructor is never called. The bits are simply copied. The original was "moved" and so nothing needs to be created or destroyed.
It will be moved. This is the prime example of a move.
There are a number of different situations that a swap
function would have to worry about if you want to make it as efficient as possible. I would advise simply using the swap function in std.algorithm. The classic swap would result in copying and would thus call the postblit constructor and the destructor. Moves are generally done by the compiler, not the programmer. However, looking at the official implementation of swap
, it looks like it plays some tricks to get move semantics out of the deal where it can. Regardless, moves are generally done by the compiler. They're an optimization that it will do where it knows that it can (RVO being the classic case where it can).
According to TDPL (p. 251), there are only 2 cases where D guarantees that a move will take place:
- All anonymous rvalues are moved, not copied. A call to
this(this
) is never inserted when the source is an anonymous rvalue (i.e., a temporary as featured in the functionhun
above).- All named temporaries that are stack-allocated inside a function and then returned elide a call to
this(this)
.- There is no guarantee that other potential elisions are observed.
So, the compiler may use moves elsewhere, but there's no guarantee that it will.
As far as I understand:
1) When a struct is copied, as opposed to moved or constructed.
2) The point of move semantics is that neither of the two needs to happen. The new location of the struct is initialized with a bit-wise copy of the struct, and the old location goes out of scope and becomes inaccessible. Thus, the struct has "moved" from A to B.
3) That is the typical move situation:
S init(bool someFlag)
{
S s;
s.foo = someFlag? bar : baz;
return s; // `s` can now be safely moved from here...
}
// call-site:
S s = init(flag);
//^ ... to here.