Functions using malloc (style)

Richard Harter rh at smds.UUCP
Sat Jun 29 17:51:38 AEST 1991


Steven Lee writes:

>   When you write a C function and it returns a pointer to some
>   structure, how should the function do this?  Many of the system
>   functions I know create a static area that gets rewritten when
>   the user makes multiple calls to it.  This avoids the problem
>   of allocating memory each time the function is called.

>   The possible solutions I have come up with are:
>   1. Force the user to malloc his own space and then call the function.

>   2. The function mallocs space each time it is called.  It is up to
>      the user to free (release) the memory.

These two choices reflect different modes of usage by the user.  Thus
(1) takes the view that the lifetime of the object specified by
the pointer is at most from one call to the function to the next.
On the other hand (2) essentially says that the user dictates the
lifetime of the object and is therefore responsible for its disposition.

Either view may be appropriate, depending on usage.  The problem is that
the function writer does not necessarily know what the users needs are.

For a bit of extra work you can accomodate both sets of needs.  Make a
package out of it.  The package has three entry points (public methods),
a get_instance, a reserve, and a release.  The get_instance returns a
pointer which is guaranteed until the next call.  The reserve makes the
object pointed to persistent until it is released.

Internally the package maintains a list of objects under management with
a private list of structures which track the objects.  For example
suppose the returned structure type is FOOBY.  The internal structure
looks like

	struct manager {
		struct manager *link;
		struct OBJECT *ptr;
		};

with private data 

	static struct manager *in_use = 0;
	static struct OBJECT *current = 0;

In a simple implementation (i.e. without multiple reserves and reference
counts) a get_instance reuses the current if it exists, otherwise it
mallocs one to create a current.  A reserve mallocs a manager struct,
puts the current in it, adds the manager struct to the in_use list, and
zeroes current.  A release searches the in_use list for the corresponding
manager struct, removes it, and either frees the contained OBJECT if
current is non zero else sets current to point to the contained object.
Finally it frees the manager struct space.

The above implementation requires extra mallocs and frees for reserved
objects.  An obvious modification is to add a current_mgr item which
eliminates the bulk of malloc/free cycles.  An more memory intensive
but more general method is to have a free list for manager structs.

A rather more general approach is to have a generic object manager
which can handle structures generically.  You can either use reference
counts or user reservation or both.  User reservation works like this:
The generic object manager package has an entry point which returns
a "user id".  The reserve function has two arguments, an object pointer
and a "user id".  There is a terminate_user function which releases
all objects reserved by the "user id".  This is a fair bit of work.
The simple implementation, however, is very easy and can be canned into
include file macros.
-- 
Richard Harter, Software Maintenance and Development Systems, Inc.
Net address: jjmhome!smds!rh Phone: 508-369-7398 
US Mail: SMDS Inc., PO Box 555, Concord MA 01742
This sentence no verb.  This sentence short.  This signature done.



More information about the Comp.lang.c mailing list