Specifying @nogc on structs seems to have no effect

Neia Neutuladh neia at ikeran.org
Tue Sep 19 20:57:17 UTC 2017


On Tuesday, 19 September 2017 at 15:11:31 UTC, Craig Black wrote:
> Thank you for the information.  What I would like to do is to 
> create an Array template class that doesn't use GC at all.

You want to ensure that it can never refer to GC memory. The type 
system does not contain that information. It doesn't say whether 
an object was allocated on the GC heap, on the stack, using 
malloc, using a whole page of memory with mmap, using hardware 
addresses directly on an embedded system with manually planned 
memory layout, using a well-known address range like VGA, as part 
of the binary's static data segment...

So @nogc can't help you. You could, however, replace the GC 
implementation with one that throws an AssertError whenever the 
GC runs a collection, allocates memory, etc. Or you could just 
add @nogc to your main function.

If you want to forbid all reference types, you could write a 
`containsReferenceTypes` template, something like:

enum containsReferenceTypes(T) =
   is(T == class) ||
   is(T == interface) ||
   isDynamicArray!T ||
   isDelegate!T ||
   (isStruct!T && hasReferenceField!T);

bool hasReferenceField(T)()
{
   static foreach (t; Fields!T)
   {
     if (containsReferenceTypes!t) return true;
   }
   return false;
}

struct Array(T) if (!containsReferenceTypes!T)
{
}

> Unfortunately I don't think this is possible with D in its 
> current state, at least not safely anyway.  As it is, I can't 
> prevent someone using my Array template to create an array of 
> objects that reference the GC heap.  This means that in order 
> to not break the language and avoid memory leaks, I am forced 
> to tell the GC to scan all of my allocations.  There seems to 
> be no way to avoid this unnecessary overhead.

That's use-after-free, not memory leaks. The GC doesn't watch to 
see when things go out of scope; it periodically scans the world 
to see what's still in scope.

> I realize that the GC will not collect during a @nogc function.
>  This is a good guarantee, but I want to reduce the amount of 
> time it takes to perform a collection, and there doesn't seem 
> to be a good way to do this.

The GC is smart enough to not scan something for pointers if it 
doesn't contain pointers. So if you have `new Vec4[100]`, for 
instance, the GC isn't going to waste time scanning the memory it 
points to.

So if you have an Array!int variable in a GC'd object, it's 
basically a pointer and a length. The GC will note that the block 
of memory it points to has a reference to it and should not be 
disposed of. It will at some point consider doing a scan on that 
block of memory, see that it has no pointers in it, and skip over 
it.


More information about the Digitalmars-d mailing list