Search code examples
copaque-pointers

How to disable integer assignment (0) to an opaque variable?


I have a module whose implementation I want to hide from its clients.

I chose to declare an opaque type which is actually a pointer to structure to be defined only in the implementation.

It all is working fine, except that I can assign the zero value to a variable of this type, which I want to avoid.

Here's an example in C.

header file foo.h

/* foo.h */
typedef struct foo *foo_t; /* <- sorry this was obviously flawed, the '*' was missing */


extern void foo_create( foo_t *t );
extern void foo_destroy( foo_t *t );
extern void foo_tile( foo_t x );

implementation file foo.c

/* foo.c */

#include <stdlib.h>

#include "foo.h"

struct foo {
    int some_member;
};

void foo_create( foo_t *t )
{
    if ( *t==0 ) {
        *t = malloc( sizeof(struct foo) );         
    }
}

void foo_destroy( foo_t *t )
{
    if ( *t!=0 ) {
        free(*t);
        *t    = 0;
    }
}


void foo_tile( foo_t t )
{
    t->some_member++;
}

And now here is an example client that uses the module: bar.c:

#include "foo.h"

int main( int argc , char **argv )
{
    foo_t toe;

    foo_create( &toe );
    toe    = 0;  /* <-- How to make the compiler (gcc) refuse this? */
    toe    = 1;  /* <--- the compiler rejects this YAY!!            */
}

The opaque type is actually a pointer to a dynamically allocated structure; If I assign the value 0 to it I incur a memory leak which could be avoided If the compiler denied the assignment of 0 to this opaque pointer.

Assigning non-null values to the pointer isn't accepted by the compiler, so I supose that with a little more effort the same could be achieved for zero value.

Is it possible to disable this assignment? How can I achieve that? If using some bit of C++ or gcc specific constructs is needed, I'll be ok with that, although a pure C solution would be nice.

Thanks in advance.


Solution

  • I'm not sure you can do it that way. The compiler would fail in main():

        toe    = 0;  /* <-- How to make the compiler (gcc) refuse this? */
    

    It would also fail in foo_destroy():

        void foo_destroy( foo_t *t )
        {
            if ( *t!=0 ) {
                free(*t);
                *t    = 0;  /* compiler refuses this also */
            }
        }
    

    You might try returning the allocated memory from foo_create() directly rather than passing in the foo_t parameter (emulating a constructor):

    extern foo_t * foo_create( void );
    
    foo_t * foo_create( void )
    {
        foo_t * t;
    
        t = malloc( sizeof(struct foo) );  
    
        return(t);       
    }
    
    int main( int argc , char **argv )
    {
        foo_t * toe;
    
        toe = foo_create();
    
        toe = 0; /* Clearly a memory leak via reassignment */
        ...
    }