Makes sense. I was uncommenting unit tests one-by-one after
making some changes when I triggered this. I guess they were
passing before because subsequent unit tests cleared the pointers
off the stack. I guess I can just call a function that allocates
a large zeroed-out array on the stack in the last unit test
before checking the count if this happens again.
Thanks

Makes sense. I was uncommenting unit tests one-by-one after
making some changes when I triggered this. I guess they were
passing before because subsequent unit tests cleared the
pointers off the stack. I guess I can just call a function that
allocates a large zeroed-out array on the stack in the last
unit test before checking the count if this happens again.
Thanks

Collect - is a hit to the GC, not an order. It can ignore this
request.
Also do not rely on the gc calling a dtor - it is not safe and
can be called totally randomed, so use RC instead or expicit
destroy()

Also do not rely on the gc calling a dtor - it is not safe and
can be called totally randomed, so use RC instead or expicit
destroy()

RC is not applicable. I'm doing unit tests for a non-GC container
and trying to make sure all destructors are called properly.
Example:
unittest {
auto a = List!int([S(0), S(1), S(2)]);
a.popBack();
assert(equal(a[], [S(0), S(1)]));
}
// lots of similar unittests
unittest {
import std.stdio;
GC.collect();
assert(S.count == 0);
}
So if all goes well, S.count should be zero, but the arrays I'm
testing against are being allocated on the heap. Given the
conditions of the tests, it seems like GC.collect should be able
to reclaim those arrays after the unit tests have exited, and in
most cases does.
The ideal solution though, would be to allocate those arrays on
the stack and avoid the problem altogether. There doesn't seem to
be any reasonable way to do it though.
// won't this allocate anyways?
S[2] b = [S(0), S(1)];
assert(equal(a[], b[]));
// why can't I just declare a static array inline?
assert(equal(a[], int[2]{ S(0), S(1) }));

Also do not rely on the gc calling a dtor - it is not safe and
can be called totally randomed, so use RC instead or expicit
destroy()

RC is not applicable. I'm doing unit tests for a non-GC
container and trying to make sure all destructors are called
properly.
Example:
unittest {
auto a = List!int([S(0), S(1), S(2)]);
a.popBack();
assert(equal(a[], [S(0), S(1)]));
}
// lots of similar unittests
unittest {
import std.stdio;
GC.collect();
assert(S.count == 0);
}
So if all goes well, S.count should be zero, but the arrays I'm
testing against are being allocated on the heap. Given the
conditions of the tests, it seems like GC.collect should be
able to reclaim those arrays after the unit tests have exited,
and in most cases does.
The ideal solution though, would be to allocate those arrays on
the stack and avoid the problem altogether. There doesn't seem
to be any reasonable way to do it though.
// won't this allocate anyways?
S[2] b = [S(0), S(1)];
assert(equal(a[], b[]));
// why can't I just declare a static array inline?
assert(equal(a[], int[2]{ S(0), S(1) }));

This seems to work, but I'm trying to determine if it's 100%
guaranteed safe.
Tacking on nogc doesn't seem to stop it from working, so that
checks out, but my example print's "postblit" three times:
struct S {
int x;
this(int x) nogc { this.x = x; }
this(this) nogc { printf("postblit\n"); }
}
auto s(T, size_t n)(T[n] values) nogc {
return values;
}
void main(string[] args) nogc {
foreach(ref s; [S(0), S(1), S(2)].s)
printf("%d\n", s.x);
}
So I think what's happening is that the array is moved into the
argument of s(), then copied to the return value, which resides
on the parent stack frame of s(), meaning that it's safe from the
body of the foreach clobbering it...is that correct?
Assuming this is safe though, it would be nice to eliminate the
postblits too. It seems like it should be move-move instead of a
move-copy. I tried "return move(values);" but that still didn't
help.
Thanks

That can't work and here is why: Druntime employs a
conservative GC that will treat several things as potential
pointers to GC memory. From the top of my head, the entire
stack as well as void[] arrays and unions that contain
pointers.
Some integer variable on the stack or a chunk of a void[] that
happens to have the same value as your GC pointer will keep it
alive. Same for a union of an integer and a pointer where you
have set the integer part to the address of your GC memory
chunk.
These misidentifications (false pointers) can become a real
problem on 32-bit systems, where due to the small address
space many things can look like valid pointers and keep GC
memory alive that should long since have been recycled.
P.S.: Also keep in mind that if you were to run
multi-threaded, the ptr you test for could have been recycled
and reassigned between GC.collect() and GC.addrOf(). Some
unittesting frameworks for example run the tests in parallel.
--=20
Marco