Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!think.com!samsung!uunet!zephyr.ens.tek.com!uw-beaver!mit-eddie!bbn.com!ulowell!m2c!jjmhome!smds!rh From: rh@smds.UUCP (Richard Harter) Newsgroups: comp.lang.c Subject: Re: Functions using malloc (style) Summary: Just how much work do you want to do? Message-ID: <609@smds.UUCP> Date: 29 Jun 91 07:51:38 GMT References: <2864543c.3e48@polyslo.CalPoly.EDU> <3545@unisoft.UUCP> Distribution: na Organization: SMDS Inc., Concord, MA Lines: 73 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.