On Tuesday, 26 April 2022 at 23:33:28 UTC, cc wrote:
On Tuesday, 26 April 2022 at 22:16:01 UTC, cc wrote:
Test application:
I should point out that all this stuff with saving refcounted
things to arrays and so on is extremely untested and
experimental🙄
One problem I'm seeing is the inability for a refcounted class
to pass itself to another function, since the class internals
don't see the struct wrapper.. you can pass the naked object
reference itself, and hope the reference doesn't get saved
otherwise there's your dangling pointer, but then you also have
the problem of inconsistent method declarations, with some
things taking Foo and others taking RefCounted!Foo etc...
Every night I pray for a `refcounted` keyword. Wouldn't
something like `auto foo = new refcount Foo();` be nice? Then
every class that deals with the objects could continue to be
allocator-agnostic... definitely not a trivial change though.
Yor code has antoher big problem. Class Animal has
@safe/pure/nothrow/@nogc destruction but class Cow has @system
destructor. When you assign RC!Cow to RC!Animal you can have
@safe @nogc ... function call @system destructor of Cow.
I have library with check this kind of error for you
(https://code.dlang.org/packages/btl).
If you need aliasing (your case) or weak pointers then try it.
```d
import std.stdio;
import core.memory;
import core.lifetime;
import btl.autoptr;
import btl.vector;
alias ARRAY = Vector;
alias RC = RcPtr;
class Animal {
void speak() {
writeln("Animal: ???");
}
~this()@system{} //without this code doesnt compile
}
class Cow : Animal {
ARRAY!(RC!Animal) friends; // Amazingly, this works, as
long as the array elem type is NOT the same as RC!(this class)
// otherwise we get a
forwarding error
int x;
this() { writefln("[Cow]"); }
this(int x) { this.x = x; writefln("[Cow %s]", x); }
~this() { writefln("[/Cow %s]", x); }
override void speak() {
writefln("Cow#%s: Moo.", x);
}
}
class Farm {
ARRAY!(RC!Cow) animals;
//this() {}
this(int) { writeln("[Farm]"); }
~this() {
writeln("[~Farm]");
animals.clear();
writeln("[/Farm]");
}
void pet(RC!Animal animal) {
writefln("Farm: The %s says...", animal);
animal.get.speak;
}
}
void main() {
auto used = GC.stats.usedSize;
scope(exit) assert(GC.stats.usedSize == used); // GC is
not touched!
{
assert(RC!Cow.make().get.x == 0);
assert(RC!Cow.make(99).get.x == 99);
}
RC!Animal other;
auto farm = RC!Farm.make(1);
{
auto cow = RC!Cow.make(1);
farm.get.animals ~= cow;
farm.get.animals ~= RC!Cow.make(2);
other = farm.get.animals[1];
auto cowGoesOutOfScope = RC!Cow.make(70);
}
writeln("out, should have seen Cow#70's dtor");
farm.get.animals[0] = farm.get.animals[1];
writeln("animals[0] (Cow#1) just got overwritten so we
should have seen its dtor");
farm.get.animals ~= RC!Cow.make(3);
farm.get.pet(other);
other = null;
farm = null;
writeln("done");
}
```