On Wednesday, 3 October 2018 at 14:07:58 UTC, Shachar Shemesh
wrote:
If you read the DIP, you will notice that the *address* in
which the old instance resides is quite important...
Allow me to further illustrate with something that can be written
in D today:
import std.stdio;
struct Tracker {
static int globalCounter;
int localCounter;
int* counter;
this (bool local) {
if (local) counter = &localCounter;
else counter = &globalCounter;
}
// this should be this(Tracker rhs)
void opAssign(Tracker rhs) {
// note: taking address of local parameter
// note: LDC will already 'optimize' the move which in
the absence
// of any move hooks will mess up the address; try with
DMD
printf("Address of temporary is '%x', counter points to
'%x'\n", &rhs, rhs.counter);
auto d = cast(void*) rhs.counter - cast(void*) &rhs;
printf("... which is '%ld' bytes from the address of
temporary.\n", d);
localCounter = rhs.localCounter;
counter = rhs.counter;
if (counter is &rhs.localCounter)
counter = &localCounter;
}
}
auto createCounter(bool local = true) {
Tracker result = Tracker(local);
return result;
}
auto createCounterNoNRV(bool local = true) {
return Tracker(local);
}
void main() {
Tracker stale1, stale2;
stale1 = createCounter();
stale2 = createCounter(false);
Tracker stale3, stale4;
stale3 = createCounterNoNRV();
stale4 = createCounterNoNRV(false);
}
If you run the above with DMD, you'll see what I mean about
obviating the address. If we get this(typeof(this)) (that is
*always* called on move) into the language, the behavior would be
set in stone regardless of compiler.