Proposal for dual memory management

F. Almeida francisco.m.almeida at gmail.com
Tue Jul 27 19:17:41 PDT 2010


In the spirit of accepting the decision of removing delete, I would like to present a proposal for semantics/library features that would give any
programmer the choice between managing dinamically allocated memory by himself and trusting the garbage collector to efficiently handle everything. This
would be similar to what happens in C# (minus the extra unsafe and fixed keywords), and can be considered safe.

1. As decided by the D designers, the "delete" keyword is to be removed. If the "new" keyword is kept, it is reserved to allocating memory managed by the
garbage collector for objects.

2. Two distinct heaps are available by default: the managed (garbage collected) heap and the unmanaged heap. Objects declared on one heap cannot be moved
to the other heap (Except by virtue of copying an object from the unmanaged heap to the garbage collected heap and then destroying the original, which is
the closest to a safe operation.) The garbage collector monitors the state of both, but only reads/writes the managed heap.

3. Manual memory (de)allocation, and construction/destruction of objects are separated, each is given its own function/operator. If a function is used, it
should be a function template that infers the required memory amount needed by a initialized object according to the contained data (i.e., calling
cmalloc()/cfree() without needing anything other than the object type).

The functions to take care of memory allocation/deallocation could simply be called alloc()/dealloc(). Example:

class Foo
{
  this() {}
  ~this() {}  // no object may be declared on the unmanaged heap unless there are explicit constructors/destructors.
}

Foo f1;    // Declared, not initialized.
alloc!Foo(f1); // Memory is allocated for the object. Constructor not yet called. Reference to f1 is returned.
f1 = Foo(); // Proposed syntax for construction on unmanaged heap. Only legal *after* allocating with alloc() (i.e. , the .init state is tested.)

destroy!Foo(f1); // Possible syntax for a function template that calls the destructor of Foo and reverts to .init. No deallocation occurs yet.
dealloc!Foo(f1); // Memory may only be deallocated *after* destroying the object (i.e., reverting it to initial state.)

Foo f1 = new Foo();  // The familiar syntax would be kept for creating on the managed heap, without any further intervention from the programmer.

4. Needless to say, in many cases the correct type would be inferred without any explicit template parameters (i.e., one could just write alloc(f1) instead
of alloc!Foo(f1).) Attempts to call either alloc(null), destroy(null) or dealloc(null) would result in exceptions.

5. Additional functions could be available to simplify these tasks. For example,

class Boo : Foo
{
   this() {}
   ~this() {}
}

Foo f2 = create!Foo(f2);  // Calls alloc!Foo(f2) and then calls the constructor. Equivalent to new in C++.
Foo b = create!Boo(b);  // Casts the pointer to the correct type before allocating, then calls the constructor. Again, same behavior as new.

delete(f2);  // Calls the destructor, and then deallocates. Would replace delete, except it wouldn't touch the managed heap.

I think this could be a reasonable way to keep manual memory management, at least on a superficial analysis.


More information about the Digitalmars-d mailing list