Connecting Tech Pros Worldwide Forums | Help | Site Map

Passing const void* to free()

Peter Ammon
Guest
 
Posts: n/a
#1: Nov 14 '05
Often times, I'll have some malloc()'d data in a struct that need not
change throughout the lifetime of the instance of the struct.
Therefore, the field within the struct is declared a pointer to const
[something]. But then free() complains when I pass in the pointer
because free() is declared as void free(void*). So I have to cast.

Why is it not declared as void free(const void*), which would save me
these headaches?

-Peter

Ben Pfaff
Guest
 
Posts: n/a
#2: Nov 14 '05

re: Passing const void* to free()


Peter Ammon <peter_ammon@rocketmail.com> writes:
[color=blue]
> Why is it not declared as void free(const void*), which would save me
> these headaches?[/color]

Because that would make it easily possible to try to free data
that is actually defined as constant. You can always define your
own function for freeing "const" data:
void free_const(const void *p) { free((void *) p); }
--
"To get the best out of this book, I strongly recommend that you read it."
--Richard Heathfield
Dan Pop
Guest
 
Posts: n/a
#3: Nov 14 '05

re: Passing const void* to free()


In <ccfd8i$8l$1@news.apple.com> Peter Ammon <peter_ammon@rocketmail.com> writes:
[color=blue]
>Often times, I'll have some malloc()'d data in a struct that need not
>change throughout the lifetime of the instance of the struct.
>Therefore, the field within the struct is declared a pointer to const
>[something]. But then free() complains when I pass in the pointer
>because free() is declared as void free(void*). So I have to cast.[/color]

Welcome to the world of const poisoning. Don't use const and your
troubles are gone.
[color=blue]
>Why is it not declared as void free(const void*), which would save me
>these headaches?[/color]

Because it would be semantically incorrect: this declaration promises
you that free() won't modify the data pointed to by its parameter. Or
the free() function is specified as *destroying* this data.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan.Pop@ifh.de
Emmanuel Delahaye
Guest
 
Posts: n/a
#4: Nov 14 '05

re: Passing const void* to free()


In 'comp.lang.c', Dan.Pop@cern.ch (Dan Pop) wrote:
[color=blue]
> Because it would be semantically incorrect: this declaration promises
> you that free() won't modify the data pointed to by its parameter. Or[/color]
----------------------------------------------------------------------^
Frenchism ? Do you mean 'thus' or 'however' ? Just kidding!
[color=blue]
> the free() function is specified as *destroying* this data.[/color]

--
-ed- get my email here: http://marreduspam.com/ad672570
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=c99
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/
Christopher Benson-Manica
Guest
 
Posts: n/a
#5: Nov 14 '05

re: Passing const void* to free()


Dan Pop <Dan.Pop@cern.ch> spoke thus:
[color=blue]
> Welcome to the world of const poisoning. Don't use const and your
> troubles are gone.[/color]

But if things are really const, doesn't it make some sense from a
design standpoint to declare them as such?

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Arthur J. O'Dwyer
Guest
 
Posts: n/a
#6: Nov 14 '05

re: Passing const void* to free()



On Wed, 7 Jul 2004, Christopher Benson-Manica wrote:[color=blue]
>
> Dan Pop <Dan.Pop@cern.ch> spoke thus:[color=green]
> > Welcome to the world of const poisoning. Don't use const and your
> > troubles are gone.[/color]
>
> But if things are really const, doesn't it make some sense from a
> design standpoint to declare them as such?[/color]

Of course. But Peter Ammon was declaring something as 'const' that
patently was *not* constant --- its target was being allocated and
de-allocated (changing the contents of the pointer variable as well
as the contents of the target) during its own lifetime.

"Const poisoning" is certainly an annoying problem when it arises,
but it *usually* indicates poor design, not a flaw in the language.
Certainly in this case it's a symptom of poor design --- if you're
malloc'ing and free'ing an object, it certainly shouldn't be 'const'!

-Arthur
Jack Klein
Guest
 
Posts: n/a
#7: Nov 14 '05

re: Passing const void* to free()


On 7 Jul 2004 13:09:02 GMT, Dan.Pop@cern.ch (Dan Pop) wrote in
comp.lang.c:
[color=blue]
> In <ccfd8i$8l$1@news.apple.com> Peter Ammon <peter_ammon@rocketmail.com> writes:
>[color=green]
> >Often times, I'll have some malloc()'d data in a struct that need not
> >change throughout the lifetime of the instance of the struct.
> >Therefore, the field within the struct is declared a pointer to const
> >[something]. But then free() complains when I pass in the pointer
> >because free() is declared as void free(void*). So I have to cast.[/color]
>
> Welcome to the world of const poisoning. Don't use const and your
> troubles are gone.
>[color=green]
> >Why is it not declared as void free(const void*), which would save me
> >these headaches?[/color]
>
> Because it would be semantically incorrect: this declaration promises
> you that free() won't modify the data pointed to by its parameter. Or
> the free() function is specified as *destroying* this data.[/color]

No, it is defined to do no such thing.

<quote>
7.20.3.2 The free function

Synopsis

1 #include <stdlib.h>
void free(void *ptr);

Description

2 The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation. If ptr is
a null pointer, no action occurs. Otherwise, if the argument does not
match a pointer earlier returned by the calloc, malloc, or realloc
function, or if the space has been deallocated by a call to free or
realloc, the behavior is undefined.

Returns

3 The free function returns no value.
<end quote>

Not one single word about destroying the data, or indeed any
specification at all about what happens to the contents of the memory.
In point of fact, a strictly conforming program cannot determine
whether the contents of the memory is modified in any way or not.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Stephen Sprunk
Guest
 
Posts: n/a
#8: Nov 14 '05

re: Passing const void* to free()


"Jack Klein" <jackklein@spamcop.net> wrote in message
news:pgcpe0pelmp2j7htk3oo6todqj9icsbecr@4ax.com...[color=blue]
> Not one single word about destroying the data, or indeed any
> specification at all about what happens to the contents of the memory.
> In point of fact, a strictly conforming program cannot determine
> whether the contents of the memory is modified in any way or not.[/color]

The contents of the memory might not be modified, but any use of the pointer
itself becomes undefined after calling free(), so the semantics of the
argument have changed even if the value might not have. Declaring free()'s
argument as const would be nonsensical as the pointer does not have the same
semantics after the call as it did before the call, and the value of the
pointed-to memory is undefined as well.

S

--
Stephen Sprunk "Those people who think they know everything
CCIE #3723 are a great annoyance to those of us who do."
K5SSS --Isaac Asimov

Dan Pop
Guest
 
Posts: n/a
#9: Nov 14 '05

re: Passing const void* to free()


In <pgcpe0pelmp2j7htk3oo6todqj9icsbecr@4ax.com> Jack Klein <jackklein@spamcop.net> writes:
[color=blue]
>On 7 Jul 2004 13:09:02 GMT, Dan.Pop@cern.ch (Dan Pop) wrote in
>comp.lang.c:
>[color=green]
>> In <ccfd8i$8l$1@news.apple.com> Peter Ammon <peter_ammon@rocketmail.com> writes:
>>[color=darkred]
>> >Often times, I'll have some malloc()'d data in a struct that need not
>> >change throughout the lifetime of the instance of the struct.
>> >Therefore, the field within the struct is declared a pointer to const
>> >[something]. But then free() complains when I pass in the pointer
>> >because free() is declared as void free(void*). So I have to cast.[/color]
>>
>> Welcome to the world of const poisoning. Don't use const and your
>> troubles are gone.
>>[color=darkred]
>> >Why is it not declared as void free(const void*), which would save me
>> >these headaches?[/color]
>>
>> Because it would be semantically incorrect: this declaration promises
>> you that free() won't modify the data pointed to by its parameter. Or
>> the free() function is specified as *destroying* this data.[/color]
>
>No, it is defined to do no such thing.
>
><quote>
>7.20.3.2 The free function
>
>Synopsis
>
>1 #include <stdlib.h>
> void free(void *ptr);
>
>Description
>
>2 The free function causes the space pointed to by ptr to be
>deallocated, that is, made available for further allocation. If ptr is
>a null pointer, no action occurs. Otherwise, if the argument does not
>match a pointer earlier returned by the calloc, malloc, or realloc
>function, or if the space has been deallocated by a call to free or
>realloc, the behavior is undefined.
>
>Returns
>
>3 The free function returns no value.
><end quote>
>
>Not one single word about destroying the data, or indeed any
>specification at all about what happens to the contents of the memory.
>In point of fact, a strictly conforming program cannot determine
>whether the contents of the memory is modified in any way or not.[/color]

Learn to read, Jack, learn to read. If a block is deallocated, what
happens to the data it contained before deallocation? It becomes
irreversibly inaccessible, so *for all intents and purposes* it is
destroyed. No one cares whether it was actually touched by the execution
of free(), this is immaterial.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan.Pop@ifh.de
Dan Pop
Guest
 
Posts: n/a
#10: Nov 14 '05

re: Passing const void* to free()


In <Xns951FC02A46161hsnoservernet@212.27.42.72> Emmanuel Delahaye <emdelYOURBRA@noos.fr> writes:
[color=blue]
>In 'comp.lang.c', Dan.Pop@cern.ch (Dan Pop) wrote:
>[color=green]
>> Because it would be semantically incorrect: this declaration promises
>> you that free() won't modify the data pointed to by its parameter. Or[/color]
>----------------------------------------------------------------------^
>Frenchism ? Do you mean 'thus' or 'however' ? Just kidding![/color]
^^^^^^^^^
I am not a native French speaker, so whatever mistakes I make are very
unlikely to be caused by my French ;-)

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan.Pop@ifh.de
E. Robert Tisdale
Guest
 
Posts: n/a
#11: Nov 14 '05

re: Passing const void* to free()


Peter Ammon wrote:
[color=blue]
> Often times, I'll have some malloc()'d data in a struct that need not
> change throughout the lifetime of the instance of the struct. Therefore,
> the field within the struct is declared a pointer to const [something].
> But then free() complains[/color]

Ignore the complaint.
[color=blue]
> when I pass in the pointer because free() is declared as void free(void*).
> So I [must] cast.
> Why is it not declared as void free(const void*),
> which would save me these headaches?[/color]
[color=blue]
> cat main.c[/color]
#include <stdlib.h>
#define free(p) free((void*)p)

int main(int argc, char* argv[]) {
const
int* p = (int*)malloc(sizeof(int));
free(p);
return 0;
}
[color=blue]
> gcc -Wall -std=c99 -pedantic -o main main.c
> ./main[/color]
Old Wolf
Guest
 
Posts: n/a
#12: Nov 14 '05

re: Passing const void* to free()


Jack Klein <jackklein@spamcop.net> wrote:[color=blue]
> Dan.Pop@cern.ch (Dan Pop) wrote:[color=green]
> > Peter Ammon <peter_ammon@rocketmail.com> writes:
> >[color=darkred]
> > >Why is it not declared as void free(const void*), which would save me
> > >these headaches?[/color]
> >
> > Because it would be semantically incorrect: this declaration promises
> > you that free() won't modify the data pointed to by its parameter. Or
> > the free() function is specified as *destroying* this data.[/color]
>
> No, it is defined to do no such thing.
>
> <quote>
> 7.20.3.2 The free function
>
> Not one single word about destroying the data, or indeed any
> specification at all about what happens to the contents of the memory.
> In point of fact, a strictly conforming program cannot determine
> whether the contents of the memory is modified in any way or not.[/color]

Before "free(p)", *p has a well-defined value. After the call to free,
*p does not have a defined value. If this does not count as
"destroying" *p, I don't know what does.
The representation of the contents of unallocated memory locations
are beyond the scope of the C standard.
E. Robert Tisdale
Guest
 
Posts: n/a
#13: Nov 14 '05

re: Passing const void* to free()


Old Wolf wrote:
[color=blue]
> Jack Klein wrote:
>[color=green]
>>Dan Pop wrote:
>>[color=darkred]
>>>Peter Ammon writes:
>>>
>>>>Why is it not declared as void free(const void*),
>>>>which would save me these headaches?
>>>
>>>Because it would be semantically incorrect: this declaration promises
>>>you that free() won't modify the data pointed to by its parameter.
>>>Or the free() function is specified as *destroying* this data.[/color]
>>
>>No, it is defined to do no such thing.
>>
>><quote>
>>7.20.3.2 The free function
>>
>>Not one single word about destroying the data, or indeed any
>>specification at all about what happens to the contents of the memory.
>>In point of fact, a strictly conforming program cannot determine
>>whether the contents of the memory is modified in any way or not.[/color]
>
>
> Before "free(p)", *p has a well-defined value. After the call to free,
> *p does not have a defined value. If this does not count as
> "destroying" *p, I don't know what does.
> The representation of the contents of unallocated memory locations
> are beyond the scope of the C standard.[/color]

Well, *destroy* has a more specific meaning. For example:

typedef struct X {
size_t n;
char* p;
} X;

X X_create(size_t n) {
X x;
x.n = n;
x.p = (char*)malloc(n + 1);
return p;
}

void X_destroy(const X* p) {
free((void*)(p->p));
}

typedef struct Y {
X x;
double d;
} Y;

Y Y_create(size_t n, double d) {
Y y;
Y.x = X_create(n);
Y.d = d;
return y;
}

void Y_destroy(const Y* p) {
X_destroy(p);
}

Destroy means that
you call destructors for *all* of the data members
*before* you deallocate storage for the object itself.

Y* p = (Y*)malloc(sizeof(Y));
*p = Y_create(13, 33.0);
free(p); // error: memory leak!
Richard Bos
Guest
 
Posts: n/a
#14: Nov 14 '05

re: Passing const void* to free()


"E. Robert Tisdale" <E.Robert.Tisdale@jpl.nasa.gov> wrote:
[color=blue]
> Peter Ammon wrote:
>[color=green]
> > Often times, I'll have some malloc()'d data in a struct that need not
> > change throughout the lifetime of the instance of the struct. Therefore,
> > the field within the struct is declared a pointer to const [something].
> > But then free() complains[/color]
>
> Ignore the complaint.[/color]

Rarely a good idea. In this case, it's relatively harmless, but it's
always better to make sure you don't need to ignore compiler warnings,
if only because if you get into the habit, you will one day ignore a
warning that does mean something serious.
[color=blue][color=green]
> > when I pass in the pointer because free() is declared as void free(void*).
> > So I [must] cast.
> > Why is it not declared as void free(const void*),
> > which would save me these headaches?[/color]
>[color=green]
> > cat main.c[/color]
> #include <stdlib.h>
> #define free(p) free((void*)p)[/color]

Congratulations, you've just thrown out all type safety C could provide
you when using that function.

free(104977);

anyone?

Richard
Dan Pop
Guest
 
Posts: n/a
#15: Nov 14 '05

re: Passing const void* to free()


In <cck8hq$936$1@nntp1.jpl.nasa.gov> "E. Robert Tisdale" <E.Robert.Tisdale@jpl.nasa.gov> writes:
[color=blue]
>Peter Ammon wrote:
>[color=green]
>> Often times, I'll have some malloc()'d data in a struct that need not
>> change throughout the lifetime of the instance of the struct. Therefore,
>> the field within the struct is declared a pointer to const [something].
>> But then free() complains[/color]
>
>Ignore the complaint.[/color]

I wouldn't have expected anything less from Trollsdale.[color=blue]
>[color=green]
>> when I pass in the pointer because free() is declared as void free(void*).
>> So I [must] cast.
>> Why is it not declared as void free(const void*),
>> which would save me these headaches?[/color]
>[color=green]
> > cat main.c[/color]
> #include <stdlib.h>
> #define free(p) free((void*)p)[/color]

- Each identifier with file scope listed in any of the following
subclauses (including the future library directions) is
reserved for use as a macro name and as an identifier with
file scope in the same name space if any of its associated
headers is included.

2 No other identifiers are reserved. If the program declares or
defines an identifier in a context in which it is reserved (other
than as allowed by 7.1.4), or defines a reserved identifier as
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
a macro name, the behavior is undefined.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan.Pop@ifh.de
Peter Ammon
Guest
 
Posts: n/a
#16: Nov 14 '05

re: Passing const void* to free()


Dan Pop wrote:
[color=blue]
> In <ccfd8i$8l$1@news.apple.com> Peter Ammon <peter_ammon@rocketmail.com> writes:
>
>[color=green]
>>Often times, I'll have some malloc()'d data in a struct that need not
>>change throughout the lifetime of the instance of the struct.
>>Therefore, the field within the struct is declared a pointer to const
>>[something]. But then free() complains when I pass in the pointer
>>because free() is declared as void free(void*). So I have to cast.[/color]
>
>
> Welcome to the world of const poisoning. Don't use const and your
> troubles are gone.[/color]

I find that casting everything to void* gets rid of a lot of troubles too.
[color=blue]
>
>[color=green]
>>Why is it not declared as void free(const void*), which would save me
>>these headaches?[/color]
>
>
> Because it would be semantically incorrect: this declaration promises
> you that free() won't modify the data pointed to by its parameter. Or
> the free() function is specified as *destroying* this data.
>[/color]

But free() isn't modifying the data pointed to by its parameter: it's
modifying the semantics of the value of the parameter itself, which is a
much stronger and almost totally unique side effect, very different from
modifying the data pointed to.

int* foo = some_allocated_int_somewhere();
*foo = 0;
some_function(foo);
*foo = 1;

No matter whether some_function() is declared to take an int* or a const
int*, that code is always completely legal...unless some_function()
invokes free() somewhere. Thus free() is a very special case, and "it's
not const, so it might modify what its parameter points to" doesn't
capture what's going on at all.

It's interesting to note that a similar situation arises at the other
point where C destroys memory, namely, when an automatic variable goes
out of scope:

const char* function(void) {
const char buff[] = "I am const";
return buff;
}

buff is defined to be const, but all the constness in the world can't
save it from being destroyed. So that's why IMO const isn't appropriate
for expressing "data that cannot be destroyed."

Since the only restriction on free() is that the pointer value was
returned by the alloc() family of functions (or is NULL), I see no
reason to disallow const pointers to be passed in, for the same reason
we don't disallow const pointers in functions such as strcmp().

-Peter
E. Robert Tisdale
Guest
 
Posts: n/a
#17: Nov 14 '05

re: Passing const void* to free()


Peter Ammon wrote:
[color=blue]
> Often times, I'll have some malloc()'d data in a struct that need not
> change throughout the lifetime of the instance of the struct. Therefore,
> the field within the struct is declared a pointer to const [something].
> But then free() complains when I pass in the pointer
> because free() is declared as void free(void*). So I [must] cast.
>
> Why is it not declared as void free(const void*),
> which would save me these headaches?[/color]

I don't know. I don't think that there is a good reason.
The C++ 'delete' operator deletes constant ans well as variable memory:
[color=blue]
> cat main.cc[/color]
int main(int argc, char* argv[]) {
const int* p = new int[16];
delete [] p;
return 0;
}

You can redefine free(void*):
[color=blue]
> cat main.c[/color]
#include <stdlib.h>

inline static
void freeConst(const void* p) {
free((void*)p);
}

#define free(p) freeConst(p)

int main(int argc, char* argv[]) {
const void* p = malloc(16);
free(p);
return EXIT_SUCCESS;
}

to provide the same behavior.
Closed Thread