Best practices for unknown data static/dynamic allocation origin

R

riccardo

Hi,
I'm wondering what the best practice is when, within a function you need
to know if a variable was allocated statically or dynamically, in order
to eventually free it.

I'm dealing with a scheduler that consume tasks. Once a task is
consumed, the scheduler has to release the memory owned by that task,
and this is a responsibility of the scheduler only (not the one entity
that allocated the task).

Three approaches come to my mind:
1) Documentation: document the function to add a new task to the
scheduler, requesting the input argument to be a dynamically allocated task.

2) Insert a flag in the task data structure to signal its origin (static
vs dynamic).

3) malloc a task and copy data into that task. All tasks shall need to
be free @removal.

I'm currently using 3 as it seems the cleaner ans safer solution; is
this correct? Is there any other way?
RM
 
N

Nobody

I'm wondering what the best practice is when, within a function you need
to know if a variable was allocated statically or dynamically, in order
to eventually free it.

The most general case is to require the caller to provide a callback
function to free the data. For static (or automatic) storage, this can be
a no-op. Dynamic storage may require a "matching" deallocator, i.e. you
can't assume the existence of a single deallocator which works with any
and all dynamically-allocated memory.

E.g. on Windows, a program may be linked with multiple DLLs, and different
DLLs may be linked with different versions of MSVCRT. Each version of
MSVCRT maintains its own heap, so anything allocated by that version's
malloc() (etc) must be deallocated using the same version's free(). If you
use the wrong free() function, it's likely to crash.

If you have multiple pointers to dynamic storage, you may need a separate
deallocator for each one.
 
B

BartC

I'm wondering what the best practice is when, within a function you need
to know if a variable was allocated statically or dynamically, in order to
eventually free it.

I'm dealing with a scheduler that consume tasks. Once a task is consumed,
the scheduler has to release the memory owned by that task, and this is a
responsibility of the scheduler only (not the one entity that allocated
the task).

Three approaches come to my mind:
1) Documentation: document the function to add a new task to the
scheduler, requesting the input argument to be a dynamically allocated
task.

2) Insert a flag in the task data structure to signal its origin (static
vs dynamic).

3) malloc a task and copy data into that task. All tasks shall need to be
free @removal.

I'm currently using 3 as it seems the cleaner ans safer solution; is this
correct? Is there any other way?

Garbage collection?
 
E

Eric Sosman

Hi,
I'm wondering what the best practice is when, within a function you need
to know if a variable was allocated statically or dynamically, in order
to eventually free it.

You probably already know that there is no portable way to examine
a block of memory, or a pointer to a block of memory, and arrive at
the answer you seek. On some systems you might be able to convert a
pointer to an integer and make some deductions based on the integer's
value ("addresses M to N are code, N to P are stack, P to Q are data,
everything else is mallocated"), but even then there's no way to tell
whether a pointer into mallocated memory is a pointer to the start of
a mallocated block or to somewhere in its middle.

But the question isn't really "was it mallocated or not," rather
"should I free it?" You certainly should not free memory that wasn't
obtained from malloc, but it is not a foregone conclusion that memory
from malloc ought to be freed by this service function of yours! It
is entirely possible that the caller might have further use for the
memory after you're through with it; you're not in a position to know.
I'm dealing with a scheduler that consume tasks. Once a task is
consumed, the scheduler has to release the memory owned by that task,
and this is a responsibility of the scheduler only (not the one entity
that allocated the task).

Three approaches come to my mind:
1) Documentation: document the function to add a new task to the
scheduler, requesting the input argument to be a dynamically allocated
task.

2) Insert a flag in the task data structure to signal its origin (static
vs dynamic).

3) malloc a task and copy data into that task. All tasks shall need to
be free @removal.

I'm currently using 3 as it seems the cleaner ans safer solution; is
this correct? Is there any other way?

The caller probably needs to insert some information into this
"task" object before your function can make sense of it. Perhaps you
should keep the "task" private and internal, and expose only a suite
of functions that set (and perhaps query) its characteristics:

typedef struct opaque_struct Task;
Task *newEmptyTask(void);
void setPriority(Task *task, int priority);
void setFrazzleString(Task *task, const char *frazzle);
Task *copyExistingTask(const Task *oldTask);
...
void performTask(Task *task);
void destroyTask(Task *hes_dead_jim);
...

An approach of this kind allows you to manage all the resources
of a Task internally, which you may find convenient. It also allows
you to change the nature of a Task without disturbing your clients or
even requiring their recompilation: You can quite easily add

void setColor(Task *task, TaskColor hue);

to the package, provide a suitable default color for pre-existing code
that is color-blind, and proceed merrily along. "Encapsulation" may
offer benefits that go well beyond solving your present difficulty.
 
M

Malcolm McLean

Hi,
I'm wondering what the best practice is when, within a function you need
to know if a variable was allocated statically or dynamically, in order
to eventually free it.
Another way is to provide / require a destructor. This take the task
as a pointer. If the task contains no dynamic data, it's simply a no-
op. Otherwise it frees the allocated elements. The advantage is that
you can have a tree or similar structure that is hard to create with a
single call to malloc().
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top