I hit a strange problem, which seems to be a compiler bug, but I kind of
doubt it, because it is really serious and I did not find anything in
bugzilla. So here is the example code, that behaves really not as
expected and in my understanding just plain and seriously wrong:
---
#!/usr/bin/rdmd
import std.stdio;
struct Test {
this(this) {
writeln("postblit called for: ", &this);
}
ref Test opAssign(ref Test other) {
writeln("opAssign called for: ", &this);
return this;
}
~this() {
writeln("Destructed: ", &this);
}
int buf;
}
struct TTest {
Test inner;
}
void main() {
TTest t1;
TTest t2;
writeln("t1: ", &t1.inner);
writeln("t2: ", &t2.inner);
t1=t2;
}
---
I would have expected, that opAssign is called for t1 and the
destructors of the two structs. The output:
---
./test1.d
t1: BFF57114
t2: BFF57118
postblit called for: BFF5711C
Destructed: BFF570F4
Destructed: BFF57118
Destructed: BFF57114
---
So instead of opAssign postblit gets called and not even for one of the
two created structs but for some temporary (BFF5711C)? This alone would
be already wrong behaviour, but to make matters worse, for this
temporary not even the destructor is called, instead the destructor of
some other unknown object gets called: BFF570F4.
Does someone have a clue what is going on? Is there a bug report I
missed?
Btw. if you replace t1=t2; with t1.inner=t2.inner; everything works as
expected.

Btw. if you replace t1=t2; with t1.inner=t2.inner; everything
works as
expected.

What you are seeing is move semantics in action:
When you call t1 = t2, it calls the compiler generated:
"opAssign(TTest other)"
As you can see, pass by value, so a new TTest is created by
postblit, in the scope of main: "BFF5711C". This new copy is then
*moved* into the scope of opAssign. At the end of opAssign, it is
the moved object that is destroyed: "BFF570F4". As for the
original object, since the compiler knows it was moved, it
doesn't call the destroyer on it.
Then, at the end of the function, your t1 and t2 are destroyed.
--------
The fact that "opAssign called for: " is not printed is, AFAIK, a
HUGE and old standing bug: The fields of the struct are bit
copied (!)
Frankly, I have no idea why it isn't fixed yet...
To "bypass" this "bug", simply define an opAssign yourself.

--------
The fact that "opAssign called for: " is not printed is, AFAIK,
a HUGE and old standing bug: The fields of the struct are bit
copied (!)
Frankly, I have no idea why it isn't fixed yet...
To "bypass" this "bug", simply define an opAssign yourself.

This should be a compiler error or at the very least issue a
warning.
It seems to me that overridden sub-struct opAssign needs to be
chained together, and it's a compiler error if there's a break in
the chain, i.e., if a sub-level struct has non-default opAssign,
then the parent must have one too, else it's an error.
--rt

This should be a compiler error or at the very least issue a
warning.
It seems to me that overridden sub-struct opAssign needs to be
chained together, and it's a compiler error if there's a break in
the chain, i.e., if a sub-level struct has non-default opAssign,
then the parent must have one too, else it's an error.

The default generated should simply call the user specified ones of any
sub struct.
Where can I find this bug? When searching for opAssign I can't find it.
I would like to vote for it.

--------
The fact that "opAssign called for: " is not printed is, AFAIK, a
HUGE and old standing bug: The fields of the struct are bit
copied (!)

I now re-read the section in TDPL about move semantics:
First off, D objects must be relocatable, ...
Well now I know why I got a problem, mine are not (not in the example
but in https://github.com/eskimor/phobos/blob/new_signal/std/signals.d
).
I register a delegate to a struct method in the postblit constructor, so
it is not relocatable, that is why things break so horrible. I
deregister the delegate in the destructor, but because of the move
semantics the deregistering is done for the wrong struct.
So in fact the only solution is to forbid copying the struct at all,
which might be the better solution anyway.
Thanks a lot! This really helped.
Best regards,
Robert