First of all: I apologize for my bad english.

In the last few weeks I searched for a way to allocate nicely temporary buffer of unknown lengths. Since D has no VLA's like C (and alloca works only partial for some strange reason: https://d.puremagic.com/issues/show_bug.cgi?id=3753), malloc / free was obiously the solution, but you have only two choices: 1. Allocate them (and maybe slice them) and free the ptr at the end of the scope (or use scope(exit)). But: Make sure that your array has not been taken over by the GC, because you made a mistake [1].

Example:
----
int* ptr = .malloc(N * int.sizeof); /// N is a runtime lengths
int[] arr = ptr[0 .. N]; /// optional slice
scope(exit) .free(ptr); // or more dangerous: free(arr.ptr);
----

Fail example:
----
int[] arr = (cast(T*) .malloc(N * int.sizeof))[0 .. N];
arr ~= 42; /// <-- [1]
scope(exit) .free(arr.ptr);
/*
* Because you don't thought about that 'arr' is a full filled array and nothing you can append to, * the GC takes over the memory and you don't have a chance to get the right C pointer to free your C memory: memory leak [A -nogc flag would maybe help here]
 */
----

2. Use a struct.
----
struct Temp(T) {
    T* ptr;
        
        alias ptr this;
        
        this(size_t N) {
                this.arr = cast(T*) .malloc(N * T.sizeof);
        }
        
        ~this() {
                .free(this.ptr);
        }
}

Temp!int arr = Temp!int(512); /// arr is destroyed at the end of the scope
----

But that does not look very nice (especially because Temp!int does not indicate that it holds an array).
Something like:
----
int[] arr = new int[512];
----
Looks nicer and more intuitive. But: it is controlled by the GC. If you want to destroy it, you have to call GC.free manually. So we have the same problems/options to destroy it as with malloc/free.

During the std.allocator thread I had made ​​the suggestion to use this allocators for such temporary arrays (See also Andrej Mitrovic post: http://forum.dlang.org/thread/l4btsk$5u8$1...@digitalmars.com?page=2#post-mailman.2478.1382651916.1719.digitalmars-d:40puremagic.com)
For example:
----
Mallocator m;
with (m) {
        int[] arr;
arr ~= 42; /// use Mallocator m for memory allocation [Question is: when it is freed? At the end of the scope? Maybe we need a (Temp|Scope)Alloc]
}
----

Or, even better.
----
with (Mallocator) {
        int[] arr;
arr ~= 42; /// use Mallocator for memory allocation [Same question]
}
----

Yet another idea of mine was:
----
int[] arr;
arr.use(Mallocator);
----

Or something better: "use" blocks:
----
use (Mallocator) {
        int[] arr;
}

arr ~= 42; /// use Mallocator for memory allocation [Same question]
----

But both would bring the introduction of a new keywords with them.

Over the last few days I had a few other ideas, besides the nice stuff from std.allocator.
One of them was to use scope:
----
scope int[] arr = new int[42]; /// arr is freed at the end of the scope
----

The compiler could rewrite this e.g. with:
----
struct scoped(A : T[], T) {
        T[] arr;
        
        ~this() {
                GC.free(arr.ptr);
        }
}

scoped!(int[]) arr = new int[42]; /// arr is freed as far as scoped's DTor is called.
----
In this case we have no need to introduce a new keyword: scope is already there.

Or, to use UDA's (but they must be improved):
----
struct temp {
        void* ptr;
        
        ~this() {
            GC.free(this.ptr);
        }
}

@temp int[] arr = new int[42]; /// arr is freed as far as temp's DTor is called ( -> if temp leaves the scope)
----

The code above would be simply rewritten to:
----
int[] arr = new int[42];
temp __udatmp = temp(arr.ptr); /// temp's DTor free the whole array [Need compiler magic]
----

Another suggestion would be DIP 46 (http://wiki.dlang.org/DIP46) with a few improvements:
----
gc_push(Mallocator);

int[] arr;
arr ~= 42;

gc_pop(); /// arr is freed (maybe it would make sense if gc_pop would be automatically inserted at the end of the scope).
----

That's it so far. Any thoughts/further suggestions?

Reply via email to