scoped allocations
Namespace
rswhite4 at googlemail.com
Tue Nov 26 15:33:57 PST 2013
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?
More information about the Digitalmars-d
mailing list