On 11/10/14 3:10 AM, Tomer Filiba wrote:
The following code does not invoke S.~this. If I change `struct S` to
`class S` - it does. Memory consumption remains constant, meaning memory
is collected, but destructors are not called.

import std.stdio;
import std.conv;

struct S {
     string s;

     ~this() {
         writeln("~S");
     }
}

void main() {
     auto i = 0;
     S[] arr;

     while (true) {
         arr ~= S("hello " ~ text(i++));
         if (arr.length == 1_000_000) {
             writeln(&arr[8888], " = ", arr[8888].s);
             arr.length = 0;
         }
     }
}


Is it a bug? How can I effectively implement RAII with this behavior?

Only classes call dtors from the GC. Structs do not. There are many hairy issues with structs calling dtors from GC. Most struct dtors expect to be called synchronously, and are not expecting to deal with multithreading issues.

Note that structs inside classes WILL call dtors.

For example, imagine you have a struct that increments/decrements a reference count:

struct refCounter(T)
{
   T t; // assume this to be a reference type
   this(T t) { t.inc();}
   ~this() {if(t !is null) t.dec();}
}

Of course, you would need more machinery to deal with copies, but let's just assume that is also implemented.

You can see how this would be some kind of useful guard using RAII on the stack.

Now, imagine you wanted to put this on the GC heap, and the GC would call struct dtors. And let's say the program is multi-threaded. First, the memory referred to by t isn't guaranteed to be alive, it could have already been finalized and freed. Second, the thread that calls the destructor may not be the thread that owns t. This means that two threads could potentially be calling t.inc() or t.dec() at the same time, leading to race conditions.

Note, even D's std.stdio.File is not able to deal with this properly.

The situation is, I allocate resources for my users and return them a
handle. I can't control what my users do with this handle, they might as
well append it to a dynamic array/insert to AA, and remove it eventually.
Also, the handle might be shared between several logical components, so
it's not that one of them can explicitly finalize it.

Is the resource a GC resource? If so, don't worry about it. If not, use a class to wrap the resource. At this point, that is all that D supports.

Any workaround for this? Perhaps disallow certain types be allocated by
the GC (I would actually want this feature very much)?

That would be a nice feature I think.

-Steve

Reply via email to