Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const-correctness and immutable allocated objects

During a recent discussion (see comments to this answer), R.. recommended to never create aliases for pointer-to-const types as you won't be able to deallocate the referenced objects easily in a conforming C program (remember: free() takes a non-const pointer argument and C99 6.3.2.3 only allows conversions from non-qualified to qualified).

The C language obviously assumes the existance of an owner for any allocated object, ie someone somewhere has to store a non-const pointer to the object, and this someone is responsible for deallocation.

Now, consider a library allocating and initializing objects which are non-modifyable from user-space code, so function calls always return const-qualified pointers.

Clearly, the library is the owner of the object and should retain a non-const pointer, which is somewhat silly as the user already supplies a perfectly valid, but const copy of the pointer on each library call.

To deallocate such an object, the library has to discard the const qualifier; as far as I can tell, the following

void dealloc_foo(const struct foo *foo)
{
    free((void *)foo);
}

is valid C; it would only be invalid if the foo parameter were additionally restrict-qualified.

However, casting away const seems somewhat hack-ish.

Is there another way aside from dropping the const from all return values of library functions, which would lose any information about object mutability?

like image 376
Christoph Avatar asked Oct 22 '10 18:10

Christoph


1 Answers

I don't read the same thing in 6.3.2.3. That paragraph is about conversions that happen implicitly and that don't need a casts. So an implicit conversion from a pointer-to-const object may be not permitted, but this says nothing about explicit casts.

Casts are handled in 6.5.4, and I don't see anything that would constrain you from a cast of any pointer-to-const that is by itself not const qualified with (void*). In the contrary it says

Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast.

So I read there that if you do things explicitly, they are permitted.

So I think the following is completely valid

char const *p = malloc(1);
free((void*)p);
What 6.5.4 forbits would be the following char *const p = malloc(1); free((void*)p); /* expression of cast is const qualified */

As a side note, for your second line of thoughts, a library that returns a pointer-to-const qualified object that then is to be placed in the responsibility of the caller, makes not much sense to me. Either

  • the library returns a pointer to an internal object, then it should qualify it pointer-to-const to have some weak protection that the caller doesn't change it, or
  • the library returns a freshly allocated object that falls in the responsibility of the caller. Then it shouldn't care much of whether the caller changes it, so it may return a pointer-to-unqualified object. If the caller then wants to ensure that the contents is not accidentally overwritten or something he might assign it to a const pointer, for his use.
like image 57
Jens Gustedt Avatar answered Oct 06 '22 01:10

Jens Gustedt