Reference counting example

vit vit at vit.vit
Wed Apr 27 06:25:42 UTC 2022


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");
     }
```


More information about the Digitalmars-d-learn mailing list